OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
t_doc_generator.cc
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  *
19  * Copyright 2006-2017 The Apache Software Foundation.
20  * https://github.com/apache/thrift
21  */
22 
23 #include <string>
24 #include <fstream>
25 #include <iostream>
26 #include <vector>
27 #include <algorithm>
28 #include <boost/algorithm/string.hpp>
29 #include <map>
30 #include <utility>
31 
32 #include <stdlib.h>
33 #include <sys/stat.h>
34 #include <sstream>
35 #include <boost/foreach.hpp>
36 #include <boost/tokenizer.hpp>
37 #include "t_generator.h"
38 #include "platform.h"
39 using namespace std;
40 
44 class t_doc_generator : public t_generator {
45  public:
47  t_program* program,
48  const map<string, string>& parsed_options,
49  const string& option_string)
50  : t_generator(program)
51  {
52  (void) parsed_options;
53  (void) option_string;
54  out_dir_base_ = "gen-doc";
55  escape_.clear();
56  escape_['&'] = "&amp;";
57  escape_['<'] = "&lt;";
58  escape_['>'] = "&gt;";
59  escape_['"'] = "&quot;";
60  escape_['\''] = "&apos;";
61  }
62 
63  struct doc_ftype {
64  enum type {
78  };
79  };
80 
81  // Sync with SandeshLevel from tools/sandesh/library/common/sandesh.sandesh
82  struct sandesh_level {
83  enum type {
85  DBG,
89  ERR,
93  };
94  };
95 
96  sandesh_level::type string_to_sandesh_level(const string &level);
97  string sandesh_level_to_string(const sandesh_level::type &slevel);
98  sandesh_level::type get_sandesh_level(t_sandesh *tsandesh);
99  string get_object_type( t_sandesh* tsandesh);
100  string get_doc_member(t_sandesh* tsandesh, string member);
101  bool is_sandesh_type(t_sandesh *tsandesh, doc_ftype::type dtype);
102  string get_doc_file_suffix(doc_ftype::type dtype);
103  string get_doc_file_description(doc_ftype::type dtype);
104  void generate_index();
105  void generate_stats_schema_program();
106  bool generate_sandesh_program(doc_ftype::type dtype);
107  void generate_const_enum_typedef_object_program();
108  void generate_doc_type(ofstream &f_out);
109  void generate_program();
110  void generate_program_toc(ofstream &f_out, string fsuffix,
111  doc_ftype::type dtype);
112  void generate_program_toc_row(t_program* tprog, ofstream &f_out,
113  string fsuffix, doc_ftype::type dtype);
114  bool generate_sandesh_program_doc(t_program* tprog, ofstream &f_out,
115  string fsuffix, doc_ftype::type dtype);
116  void generate_sandesh_program_doc_schema(t_program* tprog, ofstream &f_out,
117  string fsuffix, doc_ftype::type dtype);
118  void generate_sandesh_program_doc_schema_uve(t_program* tprog, ofstream &f_out,
119  string fsuffix);
120 
125  template <typename T>
126  void generate_stat_table_schema(string, t_field*, T*, string, vector<string>&);
127  template <typename T>
128  void generate_stat_schema_map(string, t_type*, t_type*, t_field*, T*, bool, bool, vector<string>&);
129  template <typename T>
130  void generate_stat_schema_list(string, t_type*, t_field*, T*, bool, bool, vector<string>&);
131  t_struct* find_struct_with_name(string sname);
132  template <typename T>
133  void generate_stat_schema_struct(string, t_field*, t_struct*, T*, bool, vector<string>&);
134  template <typename T>
135  void extract_tags(T*, map<string, vector<string> >&, vector<string>&, vector<string>&);
136  string generate_stat_schema_struct_base_member(string, t_field*, string, t_field*);
137  void generate_stat_table_schema_header(string, string, string, string);
138  string get_datatype_from_tfield(t_type* tfield);
139  string generate_table_entry(string name, string datatype, string index, string);
140  template <typename T>
141  string get_type_of_member(string, t_field*, t_struct*, T*);
142  string get_uve_type(string, t_field*);
143  template <typename T>
144  void populate_stat_schema_map_key_value(t_field* tfield, t_type*, t_type*, T*);
145  void generate_stat_schema_struct_members(string name, t_field*, t_struct*, vector<string>, map<string, vector<string> >, vector<string>&);
146  void is_indexed_or_suffixed_field(string, vector<string>, map<string, vector<string> >, string&, bool&, bool&);
147  template <typename T>
148  void generate_stat_schema_suffixes(string, t_field*, t_struct*, T*, map<string, vector<string> >&, vector<string>&);
149  template <typename T>
150  void generate_stat_schema_toplevel_tags(T*, vector<string>&, vector<string>&, t_field*);
151  void generate_stat_tables_schema(t_sandesh*);
152  template <typename T>
153  void generate_stat_tables_schema(T*, const vector<t_field*>, string, string, vector<string>&);
154  string get_display_name_from_comments(t_field*);
155  template <typename T>
156  void find_recursive_tags(T*, t_field*, string, string, vector<string>&);
157  template <typename T>
158  void find_recursive_tags_struct(T*, t_field*, string, string, string, vector<string>&);
159  template <typename T>
160  void find_recursive_tags_list(T*, t_field*, string, t_type*, string, vector<string>&);
161  template <typename T>
162  void find_recursive_tags_map(T*, t_field*, string, t_type*, t_type*, string, vector<string>&);
163  string find_obj_table_name(const vector<t_field*>);
164  void generate_typedef (t_typedef* ttypedef) {}
165  void generate_enum (t_enum* tenum) {}
166  void generate_const (t_const* tconst) {}
167  void generate_struct (t_struct* tstruct) {}
168  void generate_service (t_service* tservice) {}
169  void generate_sandesh (t_sandesh* tsandesh) {}
170  bool generate_introspect_cli (t_sandesh* , ofstream &f_out, bool &first_file);
171 
172  void print_doc (t_doc* tdoc, ofstream &f_out);
173  int print_type (t_type* ttype, ofstream &f_out);
174  void print_const_value(t_const_value* tvalue, ofstream &f_out);
175  void print_sandesh (t_sandesh* tdoc, ofstream &f_out);
176  void print_sandesh_message(t_sandesh* tdoc, ofstream &f_out);
177  void print_sandesh_message_table(t_sandesh* tdoc, ofstream &f_out);
178  void print_doc_string (string doc, ofstream &f_out);
179 
180  ofstream f_index_out_;
194  ofstream f_out_;
195  ofstream f_stats_tables_;
196 
197  private:
198  void generate_typedef (t_typedef* ttypedef, ofstream &f_out);
199  void generate_enum (t_enum* tenum, ofstream &f_out);
200  void generate_const (t_const* tconst, ofstream &f_out);
201  void generate_consts (vector<t_const*> consts, ofstream &f_out);
202  void generate_struct (t_struct* tstruct, ofstream &f_out);
203  void generate_struct_table (t_struct* tstruct, ofstream &f_out);
204  void generate_sandesh (t_sandesh* tsandesh, ofstream &f_out);
205  void generate_sandesh_uve (t_sandesh* tsandesh, ofstream &f_out);
206 
209 };
210 
212  doc_ftype::type dtype) {
213  t_base_type *tbtype((t_base_type *)tsandesh->get_type());
214  switch (dtype) {
215  case doc_ftype::LOGS:
216  if (tbtype->is_sandesh_system() || tbtype->is_sandesh_object()) {
217  return true;
218  }
219  return false;
220  case doc_ftype::LOGS_LEVEL_INVALID:
221  if ((tbtype->is_sandesh_system() || tbtype->is_sandesh_object()) &&
222  get_sandesh_level(tsandesh) == sandesh_level::INVALID) {
223  return true;
224  }
225  return false;
226  case doc_ftype::LOGS_LEVEL_DEBUG:
227  if ((tbtype->is_sandesh_system() || tbtype->is_sandesh_object()) &&
228  get_sandesh_level(tsandesh) == sandesh_level::DBG) {
229  return true;
230  }
231  return false;
232  case doc_ftype::LOGS_LEVEL_INFO:
233  if ((tbtype->is_sandesh_system() || tbtype->is_sandesh_object()) &&
234  get_sandesh_level(tsandesh) == sandesh_level::INFO) {
235  return true;
236  }
237  return false;
238  case doc_ftype::LOGS_LEVEL_NOTICE:
239  if ((tbtype->is_sandesh_system() || tbtype->is_sandesh_object()) &&
240  get_sandesh_level(tsandesh) == sandesh_level::NOTICE) {
241  return true;
242  }
243  return false;
244  case doc_ftype::LOGS_LEVEL_WARN:
245  if ((tbtype->is_sandesh_system() || tbtype->is_sandesh_object()) &&
246  get_sandesh_level(tsandesh) == sandesh_level::WARN) {
247  return true;
248  }
249  return false;
250  case doc_ftype::LOGS_LEVEL_ERR:
251  if ((tbtype->is_sandesh_system() || tbtype->is_sandesh_object()) &&
252  get_sandesh_level(tsandesh) == sandesh_level::ERR) {
253  return true;
254  }
255  return false;
256  case doc_ftype::LOGS_LEVEL_CRIT:
257  if ((tbtype->is_sandesh_system() || tbtype->is_sandesh_object()) &&
258  get_sandesh_level(tsandesh) == sandesh_level::CRIT) {
259  return true;
260  }
261  return false;
262  case doc_ftype::LOGS_LEVEL_ALERT:
263  if ((tbtype->is_sandesh_system() || tbtype->is_sandesh_object()) &&
264  get_sandesh_level(tsandesh) == sandesh_level::ALERT) {
265  return true;
266  }
267  return false;
268  case doc_ftype::LOGS_LEVEL_EMERG:
269  if ((tbtype->is_sandesh_system() || tbtype->is_sandesh_object()) &&
270  get_sandesh_level(tsandesh) == sandesh_level::EMERG) {
271  return true;
272  }
273  return false;
274  case doc_ftype::UVES:
275  if (tbtype->is_sandesh_uve()) {
276  return true;
277  }
278  return false;
279  case doc_ftype::TRACES:
280  if (tbtype->is_sandesh_trace() || tbtype->is_sandesh_trace_object()) {
281  return true;
282  }
283  return false;
284  case doc_ftype::INTROSPECT:
285  if (tbtype->is_sandesh_request() || tbtype->is_sandesh_response()) {
286  return true;
287  }
288  return false;
289  default:
290  return false;
291  }
292  return false;
293 }
294 
296  switch (dtype) {
297  case doc_ftype::LOGS:
298  return "_logs";
299  case doc_ftype::LOGS_LEVEL_INVALID:
300  return "_logs.invalid";
301  case doc_ftype::LOGS_LEVEL_DEBUG:
302  return "_logs.debug";
303  case doc_ftype::LOGS_LEVEL_INFO:
304  return "_logs.info";
305  case doc_ftype::LOGS_LEVEL_NOTICE:
306  return "_logs.notice";
307  case doc_ftype::LOGS_LEVEL_WARN:
308  return "_logs.warn";
309  case doc_ftype::LOGS_LEVEL_ERR:
310  return "_logs.error";
311  case doc_ftype::LOGS_LEVEL_CRIT:
312  return "_logs.crit";
313  case doc_ftype::LOGS_LEVEL_ALERT:
314  return "_logs.alert";
315  case doc_ftype::LOGS_LEVEL_EMERG:
316  return "_logs.emerg";
317  case doc_ftype::UVES:
318  return "_uves";
319  case doc_ftype::TRACES:
320  return "_traces";
321  case doc_ftype::INTROSPECT:
322  return "_introspect";
323  default:
324  return "";
325  }
326 }
327 
329  switch (dtype) {
330  case doc_ftype::LOGS:
331  return "all systemlog and objectlog";
332  case doc_ftype::LOGS_LEVEL_INVALID:
333  return "systemlog and objectlog with unknown severity";
334  case doc_ftype::LOGS_LEVEL_DEBUG:
335  return "debug systemlog and objectlog";
336  case doc_ftype::LOGS_LEVEL_INFO:
337  return "informational systemlog and objectlog";
338  case doc_ftype::LOGS_LEVEL_NOTICE:
339  return "notice systemlog and objectlog";
340  case doc_ftype::LOGS_LEVEL_WARN:
341  return "warning systemlog and objectlog";
342  case doc_ftype::LOGS_LEVEL_ERR:
343  return "error systemlog and objectlog";
344  case doc_ftype::LOGS_LEVEL_CRIT:
345  return "critical systemlog and objectlog";
346  case doc_ftype::LOGS_LEVEL_ALERT:
347  return "alert systemlog and objectlog";
348  case doc_ftype::LOGS_LEVEL_EMERG:
349  return "emergency systemlog and objectlog";
350  case doc_ftype::UVES:
351  return "UVE";
352  case doc_ftype::TRACES:
353  return "traces";
354  case doc_ftype::INTROSPECT:
355  return "introspect";
356  default:
357  return "";
358  }
359 }
360 
364 void t_doc_generator::generate_program_toc(ofstream &f_out, string fsuffix,
365  doc_ftype::type dtype) {
366  f_out << "<table><tr><th>Module</th><th>Messages</th></tr>" << endl;
367  generate_program_toc_row(program_, f_out, fsuffix, dtype);
368  f_out << "</table>" << endl;
369 }
370 
375  string fsuffix, doc_ftype::type dtype) {
376  string fname = tprog->get_name() + fsuffix + ".html";
377  f_out << "<tr>" << endl << "<td>" << tprog->get_name() << "</td><td>";
378  if (!tprog->get_sandeshs().empty()) {
379  vector<t_sandesh*> sandeshs = tprog->get_sandeshs();
380  vector<t_sandesh*>::iterator snh_iter;
381  for (snh_iter = sandeshs.begin(); snh_iter != sandeshs.end(); ++snh_iter) {
382  string name = get_sandesh_name(*snh_iter);
383  if (is_sandesh_type(*snh_iter, dtype)) {
384  if (dtype == doc_ftype::UVES) {
385  vector<t_field*> members = (*snh_iter)->get_members();
386  BOOST_FOREACH(t_field *tfield, members) {
387  name = tfield->get_type()->get_name();
388  f_out << "<a href=\"" << fname << "#Snh_" << name << "\">" << name
389  << "</a><br/>" << endl;
390  }
391  } else {
392  f_out << "<a href=\"" << fname << "#Snh_" << name << "\">" << name
393  << "</a><br/>" << endl;
394  }
395  }
396  }
397  }
398  f_out << "</td>" << endl;
399  f_out << "</tr>";
400 }
401 
402 void t_doc_generator::generate_doc_type(ofstream &f_out) {
403  f_out << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"" << endl;
404  f_out << " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" << endl;
405  f_out << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl;
406  f_out << "<head>" << endl;
407  f_out << "<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" />" << endl;
408  f_out << "<link href=\"/doc-style.css\" rel=\"stylesheet\" type=\"text/css\"/>"
409  << endl;
410 }
411 
413  string fname = get_out_dir() + program_->get_name() + "_stats_tables.json";
414  f_stats_tables_.open(fname.c_str());
415  stat_table_created_ = false;
416  first_member_ = true;
417  f_stats_tables_ << "{\"_STAT_TABLES\":[" << endl;
418  if (!program_->get_sandeshs().empty()) {
419  // Generate sandeshs
420  vector<t_sandesh*> sandeshs = program_->get_sandeshs();
421  vector<t_sandesh*>::iterator snh_iter;
422  for (snh_iter = sandeshs.begin(); snh_iter != sandeshs.end(); ++snh_iter) {
423  generate_stat_tables_schema(*snh_iter);
424  }
425  }
426  f_stats_tables_ << "]" << endl << "}" << endl;
427 }
428 
430  ofstream &f_out, string fsuffix, doc_ftype::type dtype) {
431  if (dtype == doc_ftype::UVES)
432  return generate_sandesh_program_doc_schema_uve(tprog, f_out, fsuffix);
433  bool init = false;
434  f_out << "{\"messages\":{" << endl;
435  if (!tprog->get_sandeshs().empty()) {
436  vector<t_sandesh*> sandeshs = tprog->get_sandeshs();
437  vector<t_sandesh*>::iterator snh_iter;
438  for (snh_iter = sandeshs.begin(); snh_iter != sandeshs.end(); ++snh_iter) {
439  if (!is_sandesh_type(*snh_iter, dtype)) {
440  continue;
441  }
442  if (!init) {
443  init = true;
444  } else {
445  f_out << "," << endl;
446  }
447  string sandesh_name(get_sandesh_name(*snh_iter));
448  string fname(tprog->get_name() + fsuffix + ".html");
449  f_out << "\"" << sandesh_name << "\":{\"fingerprint\":\"" <<
450  (*snh_iter)->get_ascii_fingerprint() << "\", \"href\":\"" <<
451  fname << "#Snh_" << sandesh_name << "\"";
452  if (dtype == doc_ftype::LOGS) {
453  f_out << ", \"severity\":\"" <<
454  sandesh_level_to_string(get_sandesh_level(*snh_iter)) << "\"";
455  } else if (dtype == doc_ftype::UVES) {
456  f_out << ", \"object\":\"" << get_object_type(*snh_iter) << "\"";
457  }
458  f_out << "}";
459  }
460  f_out << "}," << endl << "\"sandesh_cli\":{" << endl;
461  bool first_file = true;
462  for (snh_iter = sandeshs.begin(); snh_iter != sandeshs.end(); ++snh_iter) {
463  sandesh_name_ = get_sandesh_name(*snh_iter);
464  if (!is_sandesh_type(*snh_iter, doc_ftype::INTROSPECT)) {
465  continue;
466  }
467  generate_introspect_cli(*snh_iter, f_out, first_file);
468  }
469  f_out << endl << "}" << endl << "}" << endl;
470  } else {
471  f_out << "}" << endl << "}" << endl;
472  }
473 }
474 
476  ofstream &f_out, string fsuffix) {
477  bool init = false;
478  f_out << "{\"messages\":{" << endl;
479  if (!tprog->get_sandeshs().empty()) {
480  vector<t_sandesh*> sandeshs = tprog->get_sandeshs();
481  vector<t_sandesh*>::iterator snh_iter;
482  for (snh_iter = sandeshs.begin(); snh_iter != sandeshs.end(); ++snh_iter) {
483  if (!is_sandesh_type(*snh_iter, doc_ftype::UVES)) {
484  continue;
485  }
486  if (!init) {
487  init = true;
488  } else {
489  f_out << "," << endl;
490  }
491  string sandesh_name(get_sandesh_name(*snh_iter));
492  vector<t_field*> smembers = (*snh_iter)->get_members();
493  if (smembers.size() == 1 && smembers[0]->get_type()->is_struct()) {
494  sandesh_name = smembers[0]->get_type()->get_name();
495  }
496  string fname(tprog->get_name() + fsuffix + ".html");
497  f_out << "\"" << sandesh_name << "\":{\"fingerprint\":\"" <<
498  (*snh_iter)->get_ascii_fingerprint() << "\", \"href\":\"" <<
499  fname << "#Snh_" << sandesh_name << "\"";
500  if (get_object_type(*snh_iter) != "") {
501  f_out << ", \"object\":\"" << get_object_type(*snh_iter) << "\"";
502  }
503  f_out << "}";
504  }
505  f_out << "}," << endl << "\"sandesh_cli\":{" << endl;
506  bool first_file = true;
507  for (snh_iter = sandeshs.begin(); snh_iter != sandeshs.end(); ++snh_iter) {
508  sandesh_name_ = get_sandesh_name(*snh_iter);
509  if (!is_sandesh_type(*snh_iter, doc_ftype::UVES)) {
510  continue;
511  }
512  generate_introspect_cli(*snh_iter, f_out, first_file);
513  }
514  f_out << endl << "}" << endl << "}" << endl;
515  } else {
516  f_out << "}" << endl << "}" << endl;
517  }
518 }
519 
521  ofstream &f_out, string fsuffix, doc_ftype::type dtype) {
522 
523  generate_doc_type(f_out);
524 
525  string mdesc(get_doc_file_description(dtype));
526  f_out << "<title>Documentation for " << mdesc << " messages in " <<
527  "module: " << tprog->get_name() << "</title></head><body>" << endl <<
528  "<h1>Documentation for " << mdesc << " messages in module: "
529  << tprog->get_name() << "</h1>" << endl;
530 
531  print_doc(tprog, f_out);
532 
533  generate_program_toc(f_out, fsuffix, dtype);
534 
535  bool init = false;
536  if (!tprog->get_sandeshs().empty()) {
537  f_out << "<hr/><h2 id=\"Messages\">Messages</h2>" << endl;
538  vector<t_sandesh*> sandeshs = tprog->get_sandeshs();
539  vector<t_sandesh*>::iterator snh_iter;
540  for (snh_iter = sandeshs.begin(); snh_iter != sandeshs.end(); ++snh_iter) {
541  if (!is_sandesh_type(*snh_iter, dtype)) {
542  continue;
543  }
544  init = true;
545  sandesh_name_ = get_sandesh_name(*snh_iter);
546  f_out << "<div class=\"definition\">";
547  if (dtype == doc_ftype::UVES) {
548  generate_sandesh_uve(*snh_iter, f_out);
549  } else {
550  generate_sandesh(*snh_iter, f_out);
551  }
552  f_out << "</div>";
553  }
554  }
555  f_out << "</body></html>" << endl;
556  return init;
557 }
558 
560  string fsuffix = get_doc_file_suffix(dtype);
561 
562  string fname = get_out_dir() + program_->get_name() + fsuffix + ".html";
563  ofstream f_out;
564  f_out.open(fname.c_str());
565  bool init(generate_sandesh_program_doc(program_, f_out, fsuffix, dtype));
566  f_out.close();
567 
568  string fname_schema = get_out_dir() + program_->get_name() + fsuffix + ".doc.schema.json";
569  ofstream f_out_schema;
570  f_out_schema.open(fname_schema.c_str());
571  generate_sandesh_program_doc_schema(program_, f_out_schema, fsuffix, dtype);
572  f_out_schema.close();
573  return init;
574 }
575 
577  string fsuffix = "";
578  string fname = get_out_dir() + program_->get_name() + fsuffix + ".html";
579  f_out_.open(fname.c_str());
580 
581  generate_doc_type(f_out_);
582  f_out_ << "<title>Documentation for constants, enums, types, and data structures in " <<
583  "module: " << program_->get_name() << "</title></head><body>" << endl <<
584  "<h1>Documentation for constants, enums, types, and data structures in module: "
585  << program_->get_name() << "</h1>" << endl;
586 
587  print_doc(program_, f_out_);
588 
589  if (!program_->get_consts().empty()) {
590  f_out_ << "<hr/><h2 id=\"Constants\">Constants</h2>" << endl;
591  vector<t_const*> consts = program_->get_consts();
592  f_out_ << "<table>";
593  f_out_ << "<tr><th>Constant</th><th>Type</th><th>Value</th></tr>" << endl;
594  generate_consts(consts, f_out_);
595  f_out_ << "</table>";
596  }
597 
598  if (!program_->get_enums().empty()) {
599  f_out_ << "<hr/><h2 id=\"Enumerations\">Enumerations</h2>" << endl;
600  // Generate enums
601  vector<t_enum*> enums = program_->get_enums();
602  vector<t_enum*>::iterator en_iter;
603  for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
604  generate_enum(*en_iter, f_out_);
605  }
606  }
607 
608  if (!program_->get_typedefs().empty()) {
609  f_out_ << "<hr/><h2 id=\"Typedefs\">Type declarations</h2>" << endl;
610  // Generate typedefs
611  vector<t_typedef*> typedefs = program_->get_typedefs();
612  vector<t_typedef*>::iterator td_iter;
613  for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
614  generate_typedef(*td_iter, f_out_);
615  }
616  }
617 
618  if (!program_->get_objects().empty()) {
619  f_out_ << "<hr/><h2 id=\"Structs\">Data structures</h2>" << endl;
620  // Generate structs and exceptions in declared order
621  vector<t_struct*> objects = program_->get_objects();
622  vector<t_struct*>::iterator o_iter;
623  for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
624  generate_struct(*o_iter, f_out_);
625  }
626  }
627 
628  f_out_ << "</body></html>" << endl;
629  f_out_.close();
630 }
631 
636  string index_fname = get_out_dir() + program_->get_name() + "_index.html";
637  f_index_out_.open(index_fname.c_str());
638  f_index_out_ << "<html>" << endl;
639  f_index_out_ << "<head>Documentation for " << program_->get_name() << "</head>" << endl;
640  f_index_out_ << "<link href=\"/doc-style.css\" rel=\"stylesheet\" type=\"text/css\"/>"
641  << endl;
642  f_index_out_ << "<table><tr><th>Message Types</th></tr>" << endl;
643  if (f_log_initialized_) {
644  f_index_out_ << "<tr><td><a href=" << program_->get_name() <<
645  get_doc_file_suffix(doc_ftype::LOGS) << ".html>All Logs</a></td></tr>" << endl;
646  }
647  if (f_log_emerg_initialized_) {
648  f_index_out_ << "<tr><td><a href=" << program_->get_name() <<
649  get_doc_file_suffix(doc_ftype::LOGS_LEVEL_EMERG) << ".html>Emergency Logs</a></td></tr>" << endl;
650  }
651  if (f_log_alert_initialized_) {
652  f_index_out_ << "<tr><td><a href=" << program_->get_name() <<
653  get_doc_file_suffix(doc_ftype::LOGS_LEVEL_ALERT) << ".html>Alert Logs</a></td></tr>" << endl;
654  }
655  if (f_log_crit_initialized_) {
656  f_index_out_ << "<tr><td><a href=" << program_->get_name() <<
657  get_doc_file_suffix(doc_ftype::LOGS_LEVEL_CRIT) << ".html>Critical Logs</a></td></tr>" << endl;
658  }
659  if (f_log_error_initialized_) {
660  f_index_out_ << "<tr><td><a href=" << program_->get_name() <<
661  get_doc_file_suffix(doc_ftype::LOGS_LEVEL_ERR) << ".html>Error Logs</a></td></tr>" << endl;
662  }
663  if (f_log_warn_initialized_) {
664  f_index_out_ << "<tr><td><a href=" << program_->get_name() <<
665  get_doc_file_suffix(doc_ftype::LOGS_LEVEL_WARN) << ".html>Warning Logs</a></td></tr>" << endl;
666  }
667  if (f_log_notice_initialized_) {
668  f_index_out_ << "<tr><td><a href=" << program_->get_name() <<
669  get_doc_file_suffix(doc_ftype::LOGS_LEVEL_NOTICE) << ".html>Notice Logs</a></td></tr>" << endl;
670  }
671  if (f_log_info_initialized_) {
672  f_index_out_ << "<tr><td><a href=" << program_->get_name() <<
673  get_doc_file_suffix(doc_ftype::LOGS_LEVEL_INFO) << ".html>Informational Logs</a></td></tr>" << endl;
674  }
675  if (f_log_debug_initialized_) {
676  f_index_out_ << "<tr><td><a href=" << program_->get_name() <<
677  get_doc_file_suffix(doc_ftype::LOGS_LEVEL_DEBUG) << ".html>Debugging Logs</a></td></tr>" << endl;
678  }
679  if (f_log_invalid_initialized_) {
680  f_index_out_ << "<tr><td><a href=" << program_->get_name() <<
681  get_doc_file_suffix(doc_ftype::LOGS_LEVEL_INVALID) << ".html>Unknown severity logs</a></td></tr>" << endl;
682  }
683  if (f_uve_initialized_) {
684  f_index_out_ << "<tr><td><a href=" << program_->get_name() << "_uves.html>UVEs</a></td></tr>" << endl;
685  }
686  if (f_trace_initialized_) {
687  f_index_out_ << "<tr><td><a href=" << program_->get_name() << "_traces.html>Traces</a></td></tr>" << endl;
688  }
689  if (f_introspect_initialized_) {
690  f_index_out_ << "<tr><td><a href=" << program_->get_name() << "_introspect.html>Request-Response</a></td></tr>" << endl;
691  }
692  f_index_out_ << "</table>" << endl;
693  f_index_out_ << "</html>" << endl;
694  f_index_out_.close();
695 }
696 
702  // Make output directory
703  MKDIR(get_out_dir().c_str());
704  generate_stats_schema_program();
705  f_log_initialized_ = generate_sandesh_program(doc_ftype::LOGS);
706  f_log_invalid_initialized_ = generate_sandesh_program(doc_ftype::LOGS_LEVEL_INVALID);
707  f_log_debug_initialized_ = generate_sandesh_program(doc_ftype::LOGS_LEVEL_DEBUG);
708  f_log_info_initialized_ = generate_sandesh_program(doc_ftype::LOGS_LEVEL_INFO);
709  f_log_notice_initialized_ = generate_sandesh_program(doc_ftype::LOGS_LEVEL_NOTICE);
710  f_log_warn_initialized_ = generate_sandesh_program(doc_ftype::LOGS_LEVEL_WARN);
711  f_log_error_initialized_ = generate_sandesh_program(doc_ftype::LOGS_LEVEL_ERR);
712  f_log_crit_initialized_ = generate_sandesh_program(doc_ftype::LOGS_LEVEL_CRIT);
713  f_log_alert_initialized_ = generate_sandesh_program(doc_ftype::LOGS_LEVEL_ALERT);
714  f_log_emerg_initialized_ = generate_sandesh_program(doc_ftype::LOGS_LEVEL_EMERG);
715  f_uve_initialized_ = generate_sandesh_program(doc_ftype::UVES);
716  f_trace_initialized_ = generate_sandesh_program(doc_ftype::TRACES);
717  f_introspect_initialized_ = generate_sandesh_program(doc_ftype::INTROSPECT);
718  generate_index();
719  generate_const_enum_typedef_object_program();
720 }
721 
722 void t_doc_generator::print_doc_string(string doc, ofstream &f_out) {
723  size_t index;
724  while ((index = doc.find_first_of("\r\n")) != string::npos) {
725  if (index == 0) {
726  f_out << "<p/>" << endl;
727  } else {
728  f_out << doc.substr(0, index) << endl;
729  }
730  if (index + 1 < doc.size() && doc.at(index) != doc.at(index + 1) &&
731  (doc.at(index + 1) == '\r' || doc.at(index + 1) == '\n')) {
732  index++;
733  }
734  doc = doc.substr(index + 1);
735  }
736  f_out << doc << "<br/>";
737 }
738 
743 void t_doc_generator::print_doc(t_doc* tdoc, ofstream &f_out) {
744  if (tdoc->has_doc()) {
745  string doc = tdoc->get_doc();
746  print_doc_string(doc, f_out);
747  }
748 }
749 
750 void t_doc_generator::print_sandesh_message(t_sandesh* tsandesh, ofstream &f_out) {
751  bool first = true;
752  // Print the message
753  vector<t_field*> members = tsandesh->get_members();
754  BOOST_FOREACH(t_field *tfield, members) {
755  if (tfield->get_auto_generated()) {
756  continue;
757  }
758  if (first) {
759  f_out << "<tr><th>Message</th><td>";
760  }
761  t_type *type = tfield->get_type();
762  if (type->is_static_const_string()) {
763  t_const_value* default_val = tfield->get_value();
764  if (!first) {
765  f_out << " ";
766  }
767  f_out << get_escaped_string(default_val);
768  } else {
769  f_out << "<code>";
770  if (!first) {
771  f_out << " ";
772  }
773  f_out << tfield->get_name() << "</code>";
774  }
775  first = false;
776  }
777  if (!first) {
778  f_out << "</td></tr>" << endl;
779  }
780 }
781 
782 void t_doc_generator::print_sandesh_message_table(t_sandesh* tsandesh, ofstream &f_out) {
783  f_out << "<table>";
784  print_sandesh_message(tsandesh, f_out);
785  f_out << "</table><br/>" << endl;
786 }
787 
789  const string &ilevel) {
790  string level(ilevel);
791  // Trim and convert to lower case
792  boost::algorithm::trim(level);
793  if (level.empty()) {
795  }
796  boost::algorithm::to_lower(level);
797  if (level == "debug") {
799  }
800  if (level == "informational" || level == "info") {
802  }
803  if (level == "notice") {
805  }
806  if (level == "warning" || level == "warn") {
808  }
809  if (level == "error" || level == "err") {
811  }
812  if (level == "critical" || level == "crit") {
814  }
815  if (level == "alert") {
817  }
818  if (level == "emergency" || level == "emerg") {
820  }
822 }
823 
825  const t_doc_generator::sandesh_level::type &slevel) {
826  switch (slevel) {
828  return "emergency";
830  return "criticial";
832  return "alert";
834  return "error";
836  return "warning";
838  return "notice";
840  return "informational";
842  return "debug";
844  default:
845  return "unknown";
846  }
847 }
848 
849 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
850 string t_doc_generator::get_doc_member(t_sandesh* tsandesh, string member) {
851  if (tsandesh->has_doc()) {
852  string doc = tsandesh->get_doc();
853  size_t index;
854  if ((index = doc.find_first_of("@")) != string::npos) {
855  // Skip leading documentation
856  string fdoc(doc.substr(index + 1));
857  // Extract tokens beginning with @
858  boost::char_separator<char> fsep("@");
859  tokenizer ftokens(fdoc, fsep);
860  BOOST_FOREACH(const string &f, ftokens) {
861  // Has 2 parts, the first ending with ':' or ' ' or '\t' is
862  // the type and the next is the content
863  size_t lindex;
864  if ((lindex = f.find_first_of(": \t")) != string::npos) {
865  string type(f.substr(0, lindex));
866  if (lindex + 1 < f.size() && f.at(lindex) != f.at(lindex + 1) &&
867  (f.at(lindex + 1) == ':' || f.at(lindex + 1) == '\t' ||
868  f.at(lindex + 1) == ' ')) {
869  lindex++;
870  }
871  string content(f.substr(lindex + 1));
872  if (type == member) {
873  return content;
874  }
875  }
876  }
877  }
878  }
879  return "";
880 }
881 
883  string content = get_doc_member(tsandesh, "object");
884  if (content != "") {
885  boost::algorithm::trim(content);
886  return content;
887  }
888  return " ";
889 }
890 
892  t_sandesh* tsandesh) {
893  string content = get_doc_member(tsandesh, "severity");
894  if (content != "")
895  return string_to_sandesh_level(content);
896  return sandesh_level::INVALID;
897 }
898 
904 void t_doc_generator::print_sandesh(t_sandesh* tsandesh, ofstream &f_out) {
905  if (tsandesh->has_doc()) {
906  bool table = false;
907  string doc = tsandesh->get_doc();
908  size_t index;
909  if ((index = doc.find_first_of("@")) != string::npos) {
910  // Print leading documentation
911  f_out << doc.substr(0, index) << "<p/>" << endl;
912  string fdoc(doc.substr(index + 1));
913  if (!table) {
914  f_out << "<table>" << endl;
915  print_sandesh_message(tsandesh, f_out);
916  table = true;
917  }
918  // Extract tokens beginning with @
919  boost::char_separator<char> fsep("@");
920  tokenizer ftokens(fdoc, fsep);
921  BOOST_FOREACH(const string &f, ftokens) {
922  // Has 2 parts, the first ending with ':' or ' ' or '\t' is
923  // the type and the next is the content
924  size_t lindex;
925  if ((lindex = f.find_first_of(": \t")) != string::npos) {
926  string type(f.substr(0, lindex));
927  type.at(0) = toupper(type.at(0));
928  f_out << "<tr><th>" << type << "</th>";
929  if (lindex + 1 < f.size() && f.at(lindex) != f.at(lindex + 1) &&
930  (f.at(lindex + 1) == ':' || f.at(lindex + 1) == '\t' ||
931  f.at(lindex + 1) == ' ')) {
932  lindex++;
933  }
934  string content(f.substr(lindex + 1));
935  f_out << "<td>" << content << "</td></tr>" << endl;
936  } else {
937  f_out << "<td>" << f << "</td>" << endl;
938  }
939  }
940  } else {
941  f_out << doc << "<p/>" << endl;
942  print_sandesh_message_table(tsandesh, f_out);
943  }
944  if (table) {
945  f_out << "</table><br/>" << endl;
946  }
947  } else {
948  print_sandesh_message_table(tsandesh, f_out);
949  }
950 }
951 
955 int t_doc_generator::print_type(t_type* ttype, ofstream &f_out) {
956  int len = 0;
957  f_out << "<code>";
958  if (ttype->is_container()) {
959  if (ttype->is_list()) {
960  f_out << "list&lt;";
961  len = 6 + print_type(((t_list*)ttype)->get_elem_type(), f_out);
962  f_out << "&gt;";
963  } else if (ttype->is_set()) {
964  f_out << "set&lt;";
965  len = 5 + print_type(((t_set*)ttype)->get_elem_type(), f_out);
966  f_out << "&gt;";
967  } else if (ttype->is_map()) {
968  f_out << "map&lt;";
969  len = 5 + print_type(((t_map*)ttype)->get_key_type(), f_out);
970  f_out << ", ";
971  len += print_type(((t_map*)ttype)->get_val_type(), f_out);
972  f_out << "&gt;";
973  }
974  } else if (ttype->is_base_type()) {
975  f_out << (((t_base_type*)ttype)->is_binary() ? "binary" : ttype->get_name());
976  len = ttype->get_name().size();
977  } else {
978  string prog_name = ttype->get_program()->get_name();
979  string type_name = ttype->get_name();
980  f_out << "<a href=\"" << prog_name << ".html#";
981  if (ttype->is_typedef()) {
982  f_out << "Typedef_";
983  } else if (ttype->is_struct() || ttype->is_xception()) {
984  f_out << "Struct_";
985  } else if (ttype->is_enum()) {
986  f_out << "Enum_";
987  } else if (ttype->is_service()) {
988  f_out << "Svc_";
989  }
990  f_out << type_name << "\">";
991  len = type_name.size();
992  if (ttype->get_program() != program_) {
993  f_out << prog_name << ".";
994  len += prog_name.size() + 1;
995  }
996  f_out << type_name << "</a>";
997  }
998  f_out << "</code>";
999  return len;
1000 }
1001 
1005 void t_doc_generator::print_const_value(t_const_value* tvalue, ofstream &f_out) {
1006  bool first = true;
1007  switch (tvalue->get_type()) {
1009  f_out << tvalue->get_integer();
1010  break;
1012  f_out << tvalue->get_double();
1013  break;
1015  f_out << '"' << get_escaped_string(tvalue) << '"';
1016  break;
1017  case t_const_value::CV_MAP:
1018  {
1019  f_out << "{ ";
1020  map<t_const_value*, t_const_value*> map_elems = tvalue->get_map();
1021  map<t_const_value*, t_const_value*>::iterator map_iter;
1022  for (map_iter = map_elems.begin(); map_iter != map_elems.end(); map_iter++) {
1023  if (!first) {
1024  f_out << ", ";
1025  }
1026  first = false;
1027  print_const_value(map_iter->first, f_out);
1028  f_out << " = ";
1029  print_const_value(map_iter->second, f_out);
1030  }
1031  f_out << " }";
1032  }
1033  break;
1035  {
1036  f_out << "{ ";
1037  vector<t_const_value*> list_elems = tvalue->get_list();;
1038  vector<t_const_value*>::iterator list_iter;
1039  for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) {
1040  if (!first) {
1041  f_out << ", ";
1042  }
1043  first = false;
1044  print_const_value(*list_iter, f_out);
1045  }
1046  f_out << " }";
1047  }
1048  break;
1049  default:
1050  f_out << "UNKNOWN";
1051  break;
1052  }
1053 }
1054 
1060 void t_doc_generator::generate_typedef(t_typedef* ttypedef, ofstream &f_out) {
1061  string name = ttypedef->get_name();
1062  f_out << "<div class=\"definition\">";
1063  f_out << "<h3 id=\"Typedef_" << name << "\">Typedef: " << name
1064  << "</h3>" << endl;
1065  f_out << "<p><strong>Base type:</strong>&nbsp;";
1066  print_type(ttypedef->get_type(), f_out);
1067  f_out << "</p>" << endl;
1068  print_doc(ttypedef, f_out);
1069  f_out << "</div>" << endl;
1070 }
1071 
1077 void t_doc_generator::generate_enum(t_enum* tenum, ofstream &f_out) {
1078  string name = tenum->get_name();
1079  f_out << "<div class=\"definition\">";
1080  f_out << "<h3 id=\"Enum_" << name << "\">Enumeration: " << name
1081  << "</h3>" << endl;
1082  print_doc(tenum, f_out);
1083  vector<t_enum_value*> values = tenum->get_constants();
1084  vector<t_enum_value*>::iterator val_iter;
1085  f_out << "<br/><table>" << endl;
1086  for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) {
1087  f_out << "<tr><td><code>";
1088  f_out << (*val_iter)->get_name();
1089  f_out << "</code></td><td><code>";
1090  f_out << (*val_iter)->get_value();
1091  f_out << "</code></td></tr>" << endl;
1092  }
1093  f_out << "</table></div>" << endl;
1094 }
1095 
1099 void t_doc_generator::generate_const(t_const* tconst, ofstream &f_out) {
1100  string name = tconst->get_name();
1101  f_out << "<tr id=\"Const_" << name << "\"><td><code>" << name
1102  << "</code></td><td><code>";
1103  print_type(tconst->get_type(), f_out);
1104  f_out << "</code></td><td><code>";
1105  print_const_value(tconst->get_value(), f_out);
1106  f_out << "</code></td></tr>";
1107  if (tconst->has_doc()) {
1108  f_out << "<tr><td colspan=\"3\"><blockquote>";
1109  print_doc(tconst, f_out);
1110  f_out << "</blockquote></td></tr>";
1111  }
1112 }
1113 
1114 void t_doc_generator::generate_consts(vector<t_const*> consts, ofstream &f_out) {
1115  vector<t_const*>::iterator c_iter;
1116  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
1117  generate_const(*c_iter, f_out);
1118  }
1119 }
1120 
1121 void t_doc_generator::generate_stat_table_schema_header(string type, string attr, string table_name, string display_name) {
1122  if (stat_table_created_ == false) {
1123  stat_table_created_ = true;
1124  f_stats_tables_ << "{\n\"stat_type\":\"" << type << "\"," << endl;
1125  } else {
1126  f_stats_tables_ << ",\n{\n\"stat_type\":\"" << type << "\"," << endl;
1127  }
1128  f_stats_tables_ << "\"stat_attr\":\"" << attr << "\"," << endl;
1129  f_stats_tables_ << "\"display_name\":\"" << display_name << "\"," << endl;
1130  f_stats_tables_ << "\"obj_table\": \"" << table_name << "\",\n";
1131  f_stats_tables_ << "\"attributes\":[" << endl;
1132  first_member_ = true;
1133 }
1134 
1135 string t_doc_generator::get_uve_type(string name, t_field* tfield) {
1136  map<string, string>::iterator jt;
1137  string uve_type = "";
1138  jt = tfield->annotations_.find("uve_type");
1139  if (jt != tfield->annotations_.end()) {
1140  string annotations = jt->second;
1141  boost::char_separator<char> fsep(",");
1142  tokenizer tags(tfield->annotations_["uve_type"], fsep);
1143  BOOST_FOREACH(const string &tag, tags) {
1144  size_t index = tag.find(':');
1145  if(index != string::npos) {
1146  string fname = tag.substr(0, index);
1147  boost::trim(fname);
1148  uve_type = tag.substr(index+1);
1149  boost::trim(uve_type);
1150  if (name == fname)
1151  return uve_type;
1152  }
1153  }
1154  }
1155  return "";
1156 }
1157 
1158 template <typename T>
1159 string t_doc_generator::get_type_of_member(string name, t_field* tfield, t_struct* cstruct, T* tstruct) {
1160  string datatype;
1161  vector<t_field*>::const_iterator m_iter;
1162  if (!boost::starts_with(name, ".")) {
1163  //find the member in top level structure
1164  const vector<t_field*>& tmembers = tstruct->get_members();
1165  for (m_iter = tmembers.begin(); m_iter != tmembers.end(); ++m_iter) {
1166  map<string, string>::iterator jt;
1167  if (name == (*m_iter)->get_name()) {
1168  return get_datatype_from_tfield((*m_iter)->get_type());
1169  }
1170  }
1171  } else if (name.compare(".__key") == 0) {
1172  if (tfield->get_type()->is_map()) {
1173  t_type* keytype= ((t_map*)(tfield->get_type()))->get_key_type();
1174  return get_datatype_from_tfield(keytype);
1175  }
1176  } else {
1177  const vector<t_field*>& tmembers = cstruct->get_members();
1178  for (m_iter = tmembers.begin(); m_iter != tmembers.end(); ++m_iter) {
1179  map<string, string>::iterator jt;
1180  if (name.substr(1) == (*m_iter)->get_name()) {
1181  return get_datatype_from_tfield((*m_iter)->get_type());
1182  }
1183  }
1184  }
1185  return datatype;
1186 }
1187 
1188 template <typename T>
1190  string>& top_level_tags, vector<string>& schema, t_field* tfield) {
1191  BOOST_FOREACH(const string &tag, top_level_tags) {
1192  //find the member in top level structure
1193  const vector<t_field*>& tmembers = tstruct->get_members();
1194  vector<t_field*>::const_iterator m_iter;
1195  for (m_iter = tmembers.begin(); m_iter != tmembers.end(); ++m_iter) {
1196  map<string, string>::iterator jt;
1197  if (tag == (*m_iter)->get_name()) {
1198  string fname;
1199  schema.push_back(generate_stat_schema_struct_base_member(
1200  fname, *m_iter, "true", tfield));
1201  break;
1202  }
1203  }
1204  }
1205 }
1206 
1207 template <typename T>
1209  t_field* tfield, t_struct* cstruct, T* tstruct, map<string,
1210  vector<string> >& suffixes, vector<string>& schemas) {
1211  map<string, vector<string> >::iterator it;
1212  for (it=suffixes.begin(); it!=suffixes.end(); ++it) {
1213  string fname = it->first;
1214  string datatype = get_type_of_member(fname, tfield, cstruct, tstruct);
1215  if (boost::starts_with(fname, ".")) {
1216  fname = tfield->get_name() + fname;
1217  }
1218  if (!prefix.empty()) {
1219  fname = prefix + "." + fname;
1220  }
1221  string index = "true";
1222  string suffix;
1223  vector<string>::iterator name_it;
1224  for (name_it = it->second.begin(); name_it!=it->second.end(); ++name_it) {
1225  string suffix_name = tfield->get_name() + *name_it;
1226  if (boost::starts_with(suffix_name, ".")) {
1227  suffix_name = tfield->get_name() + suffix_name;
1228  }
1229  if (!prefix.empty()) {
1230  suffix_name = prefix + "." + suffix_name;
1231  }
1232  if(name_it == it->second.begin()) {
1233  suffix = suffix + "\"" + suffix_name + "\"";
1234  } else {
1235  suffix = suffix + ", \"" + suffix_name + "\"";
1236  }
1237  }
1238  indent_up();
1239  f_stats_tables_ << "," << endl;
1240  string uve_type = get_uve_type(it->first, tfield);
1241  std::ostringstream oss;
1242  if (uve_type != "") {
1243  oss << "{\"name\":\"" << fname <<
1244  "\",\"datatype\":\"" << datatype << "\",\"index\":" << index <<
1245  ",\"uve_type\":\"" << uve_type <<
1246  "\",\"suffixes\":[" << suffix << "]}";
1247  } else {
1248  oss << "{\"name\":\"" << fname <<
1249  "\",\"datatype\":\"" << datatype << "\",\"index\":" << index <<
1250  ",\"suffixes\":[" << suffix << "]}";
1251  }
1252  schemas.push_back(oss.str());
1253  indent(f_stats_tables_) << oss.str();
1254  indent_down();
1255  }
1256 }
1257 
1259  vector<string> tags, map<string, vector<string> > suffixes,
1260  string& index, bool& is_suffixed_field, bool& is_tag) {
1261  BOOST_FOREACH(const string &tag, tags) {
1262  string field_name = string(".") + fname;
1263  string trimmed_tag = tag;
1264  boost::trim(trimmed_tag);
1265  if (trimmed_tag == field_name) {
1266  index = "true";
1267  return;
1268  }
1269  }
1270  for(map<string, vector<string> >::iterator it = suffixes.begin(); it != suffixes.end(); ++it) {
1271  string field_name = string(".") + fname;
1272  string trimmed_tag = it->first;
1273  boost::trim(trimmed_tag);
1274  if (trimmed_tag == field_name) {
1275  is_suffixed_field = true;
1276  return;
1277  }
1278  }
1279  for(map<string, vector<string> >::iterator it = suffixes.begin(); it != suffixes.end(); ++it) {
1280  string field_name = string(".") + fname;
1281  vector<string> values = it->second;
1282  BOOST_FOREACH(string value, values) {
1283  if (value == field_name) {
1284  is_tag = true;
1285  return;
1286  }
1287  }
1288  }
1289 }
1290 
1292  t_field* tfield, t_struct* tstruct, vector<string> tags,
1293  map<string, vector<string> > suffixes, vector<string>& schemas) {
1294  const vector<t_field*> members = tstruct->get_members();
1295  vector<t_field*>::const_iterator m_iter;
1296  string name = tfield->get_name();
1297  if(!prefix.empty()) {
1298  prefix = prefix + "." + name;
1299  } else {
1300  prefix = name;
1301  }
1302  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1303  string index = "false";
1304  bool is_suffixed_field = false, is_tag = false, is_index = false;
1305  is_indexed_or_suffixed_field((*m_iter)->get_name(), tags, suffixes, index, is_suffixed_field, is_tag);
1306  if (index == "true") {
1307  is_index = true;
1308  } else {
1309  is_index = false;
1310  }
1311  if (is_suffixed_field) {
1312  continue;
1313  }
1314  t_type* mtype = (*m_iter)->get_type();
1315  if(mtype->is_base_type()) {
1316  string schema = generate_stat_schema_struct_base_member(prefix, *m_iter, index, tfield);
1317  if (index == "true" || is_tag)
1318  schemas.push_back(schema);
1319  } else if (mtype->is_struct()) {
1320  string mtype_name = mtype->get_name();
1321  t_struct *cstruct = find_struct_with_name(mtype_name);
1322  if (cstruct) {
1323  generate_stat_schema_struct(prefix, (*m_iter), cstruct, tstruct, false, schemas);
1324  }
1325  } else if (mtype->is_list() || mtype->is_set()) {
1326  t_type* etype= ((t_list*)mtype)->get_elem_type();
1327  generate_stat_schema_list(prefix, etype, (*m_iter), tstruct, false, is_index, schemas);
1328  } else if (mtype->is_map()) {
1329  t_type* valtype= ((t_map*)((*m_iter)->get_type()))->get_val_type();
1330  t_type* keytype= ((t_map*)((*m_iter)->get_type()))->get_key_type();
1331  generate_stat_schema_map(prefix, keytype, valtype, (*m_iter), tstruct, false, is_index, schemas);
1332  }
1333  }
1334 }
1335 
1337  string datatype = ttype->get_name();
1338  if ((datatype == "u32") || (datatype == "u16") || (datatype == "u64"))
1339  datatype = "int";
1340  return datatype;
1341 }
1342 
1343 string t_doc_generator::generate_table_entry(string name, string datatype, string index, string uve_type) {
1344  indent_up();
1345  if (!first_member_) {
1346  f_stats_tables_ << "," << endl;
1347  }
1348  std::ostringstream oss;
1349  if (uve_type != "") {
1350  oss << "{\"name\":\"" << name << "\",\"datatype\":\""
1351  << datatype << "\",\"index\":" << index << ",\"uve_type\":\""
1352  << uve_type << "\"}";
1353  } else {
1354  oss << "{\"name\":\"" << name << "\",\"datatype\":\""
1355  << datatype << "\",\"index\":" << index << "}";
1356  }
1357  string schema = oss.str();
1358  indent(f_stats_tables_) << schema;
1359  first_member_ = false;
1360  indent_down();
1361  return schema;
1362 }
1363 
1364 template <typename T>
1365 void t_doc_generator::generate_stat_schema_map(string prefix, t_type* keytype, t_type* valtype, t_field* tfield, T* tstruct, bool is_top_level, bool is_index, vector<string>& schemas) {
1366  map<string, vector<string> > suffixes;
1367  vector<string> top_level_tags;
1368  vector<string> member_tags;
1369  bool is_empty_tag = false;
1370  map<string, string>::iterator jt;
1371  string tname = tfield->get_name();
1372  jt = tfield->annotations_.find("tags");
1373  if (jt == tfield->annotations_.end())
1374  is_empty_tag = true;
1375  if (!is_top_level && !is_empty_tag && !is_index) {
1376  return;
1377  }
1378  if(!prefix.empty()) {
1379  tname = prefix + "." + tname;
1380  }
1381  if (is_empty_tag == false) {
1382  extract_tags(tfield, suffixes, top_level_tags, member_tags);
1383  }
1384  if (!valtype->is_base_type()) {
1385  string name = tname + string(".__key");
1386  string datatype = get_datatype_from_tfield(keytype);
1387  string index = "false";
1388  bool is_suffixed_field = false, is_tag = false;
1389  is_indexed_or_suffixed_field(string("__key"), member_tags, suffixes, index, is_suffixed_field, is_tag);
1390  string uve_type = get_uve_type("__key", tfield);
1391  if (!is_suffixed_field) {
1392  string schema = generate_table_entry(name, datatype, index, uve_type);
1393  if (index == "true" || is_tag)
1394  schemas.push_back(schema);
1395  }
1396  if(valtype->is_base_type()) {
1397  name = tname + string(".__value");
1398  datatype = get_datatype_from_tfield(valtype);
1399  index = "false";
1400  BOOST_FOREACH(const string &f, member_tags) {
1401  if (f == string(".__value")) {
1402  index = "true";
1403  }
1404  }
1405  uve_type = get_uve_type("__value", tfield);
1406  generate_table_entry(name, datatype, index, uve_type);
1407  }
1408  } else {
1409  // name:"field.*" datatype:"string" for querying/selecting individual elem
1410  string name = tname + ".*";
1411  string datatype = get_datatype_from_tfield(valtype);
1412  string index = "false";
1413  if (is_index) {
1414  index = "true";
1415  }
1416  string uve_type = get_uve_type(tname, tfield);
1417  string schema = generate_table_entry(name, datatype, index, uve_type);
1418  if (index == "true") {
1419  schemas.push_back(schema);
1420  }
1421  // name:"field" datatype:"map" for selecting entire map
1422  name = tname;
1423  datatype = "map";
1424  index = "false";
1425  uve_type = get_uve_type(tname, tfield);
1426  schema = generate_table_entry(name, datatype, index, uve_type);
1427  }
1428 
1429  string empty_prefix;
1430  if (valtype->is_struct()) {
1431  string sname = valtype->get_name();
1432  t_struct *cstruct = find_struct_with_name(sname);
1433  if (cstruct) {
1434  if(!is_empty_tag) {
1435  generate_stat_schema_struct_members(empty_prefix, tfield, cstruct, member_tags, suffixes, schemas);
1436  }
1437  generate_stat_schema_toplevel_tags(tstruct, top_level_tags, schemas, tfield);
1438  generate_stat_schema_suffixes(empty_prefix, tfield, cstruct, tstruct, suffixes, schemas);
1439  }
1440  } else {
1441  generate_stat_schema_toplevel_tags(tstruct, top_level_tags, schemas, tfield);
1442  generate_stat_schema_suffixes(empty_prefix, tfield, NULL, tstruct, suffixes, schemas);
1443  }
1444 }
1445 
1447  t_field* tfield, string index, t_field* top_field) {
1448  string fname = tfield->get_name();
1449  string uve_type;
1450  if (!prefix.empty()) {
1451  uve_type = get_uve_type("." + fname, top_field);
1452  fname = prefix+ "." + fname;
1453  } else {
1454  uve_type = get_uve_type(fname, top_field);
1455  }
1456  string datatype = get_datatype_from_tfield(tfield->get_type());
1457  return generate_table_entry(fname, datatype, index, uve_type);
1458 }
1459 
1460 template <typename T>
1461 void t_doc_generator::extract_tags(T* tfield, map<string, vector<string> >
1462  &suffixes, vector<string> &top_level_tags, vector<string> &member_tags) {
1463  boost::char_separator<char> fsep(",");
1464  tokenizer tags(tfield->annotations_["tags"], fsep);
1465  BOOST_FOREACH(const string &tag, tags) {
1466  size_t index = tag.find(':');
1467  if(index != string::npos) {
1468  string fname = tag.substr(0, index);
1469  boost::trim(fname);
1470  string suffix_name = tag.substr(index+1);
1471  boost::trim(suffix_name);
1472  if(suffixes.find(fname) == suffixes.end()) {
1473  vector<string> new_suffix;
1474  new_suffix.push_back(suffix_name);
1475  suffixes.insert(make_pair(fname, new_suffix));
1476  } else {
1477  vector<string> old_suffixes = suffixes[fname];
1478  old_suffixes.push_back(suffix_name);
1479  suffixes[fname] = old_suffixes;
1480  }
1481  } else {
1482  string trimmed_tag = tag;
1483  boost::trim(trimmed_tag);
1484  if (!boost::starts_with(trimmed_tag, ".")) {
1485  top_level_tags.push_back(trimmed_tag);
1486  } else {
1487  member_tags.push_back(trimmed_tag);
1488  }
1489  }
1490  }
1491 }
1492 
1493 template <typename T>
1494 void t_doc_generator::generate_stat_schema_struct(string prefix, t_field* tfield, t_struct* cstruct, T* tstruct, bool is_top_level, vector<string>& schemas) {
1495  map<string, vector<string> > suffixes;
1496  vector<string> top_level_tags;
1497  vector<string> member_tags;
1498  bool is_empty_tag = false;
1499  if (is_top_level) {
1500  extract_tags(tfield, suffixes, top_level_tags, member_tags);
1501  } else {
1502  map<string, string>::iterator jt = tfield->annotations_.find("tags");
1503  if (jt == tfield->annotations_.end()) {
1504  is_empty_tag = true;
1505  } else {
1506  return;
1507  }
1508  }
1509  if(is_empty_tag || is_top_level)
1510  generate_stat_schema_struct_members(prefix, tfield, cstruct, member_tags, suffixes, schemas);
1511  generate_stat_schema_toplevel_tags(tstruct, top_level_tags, schemas, tfield);
1512  generate_stat_schema_suffixes(prefix, tfield, cstruct, tstruct, suffixes, schemas);
1513 }
1514 
1515 template <typename T>
1516 void t_doc_generator::generate_stat_schema_list(string name, t_type* ttype, t_field* tfield, T* tstruct, bool is_top_level, bool is_index, vector<string>& schemas) {
1517  if (ttype->is_struct()) {
1518  string sname = ttype->get_name();
1519  t_struct *cstruct = find_struct_with_name(sname);
1520  if (cstruct) {
1521  generate_stat_schema_struct(name, tfield, cstruct, tstruct, is_top_level, schemas);
1522  }
1523  } else if (ttype->is_base_type()) {
1524  map<string, vector<string> > suffixes;
1525  vector<string> top_level_tags;
1526  vector<string> member_tags;
1527  bool is_empty_tag = false;
1528  map<string, string>::iterator jt;
1529  string tname = tfield->get_name();
1530  jt = tfield->annotations_.find("tags");
1531  if (jt == tfield->annotations_.end())
1532  is_empty_tag = true;
1533  if (!is_top_level && !is_empty_tag && !is_index) {
1534  return;
1535  }
1536  if(!name.empty()) {
1537  tname = name + "." + tname;
1538  }
1539  if (is_empty_tag == false) {
1540  extract_tags(tfield, suffixes, top_level_tags, member_tags);
1541  }
1542  string datatype;
1543  if (tfield->get_type()->is_list()) {
1544  datatype = "list";
1545  } else if (tfield->get_type()->is_set()) {
1546  datatype = "set";
1547  }
1548  string index = "false";
1549  bool is_suffixed_field = false, is_tag = false;
1550  is_indexed_or_suffixed_field(tname, member_tags, suffixes, index, is_suffixed_field, is_tag);
1551  if (is_index) {
1552  index = "true";
1553  } else {
1554  index = "false";
1555  }
1556  jt = tfield->annotations_.find("uve_type");
1557  string uve_type = "";
1558  if (jt != tfield->annotations_.end())
1559  uve_type = jt->second;
1560  if (!is_suffixed_field) {
1561  string schema = generate_table_entry(tname, datatype, index, uve_type);
1562  if (is_tag || index == "true")
1563  schemas.push_back(schema);
1564  }
1565  }
1566 }
1567 
1569  t_struct *cstruct = program_->get_struct(sname.c_str());
1570  if (cstruct) {
1571  return cstruct;
1572  }
1573  // Check in includes
1574  const vector<t_program*>& includes = program_->get_includes();
1575  vector<t_program*>::const_iterator iter;
1576  for (iter = includes.begin(); iter != includes.end(); ++iter) {
1577  cstruct = (*iter)->get_struct(sname.c_str());
1578  if (cstruct) {
1579  return cstruct;
1580  }
1581  }
1582  return NULL;
1583 }
1584 
1585 template <typename T>
1586 void t_doc_generator::generate_stat_table_schema(string oname, t_field* tfield, T* tsandesh, string prefix, vector<string>& tags) {
1587  if (tfield->get_type()->is_list()) {
1588  t_type* ltype= ((t_list*)((tfield)->get_type()))->get_elem_type();
1589  generate_stat_schema_list(prefix, ltype, tfield, tsandesh, true, false, tags);
1590  } else if (tfield->get_type()->is_map()) {
1591  t_type* valtype= ((t_map*)(tfield->get_type()))->get_val_type();
1592  t_type* keytype= ((t_map*)(tfield->get_type()))->get_key_type();
1593  generate_stat_schema_map(prefix, keytype, valtype, tfield, tsandesh, true, false, tags);
1594  } else if (tfield->get_type()->is_struct()) {
1595  string sname = (tfield->get_type())->get_name();
1596  t_struct *cstruct = find_struct_with_name(sname);
1597  if (cstruct) {
1598  generate_stat_schema_struct(prefix, tfield, cstruct, tsandesh, true, tags);
1599  }
1600  }
1601 }
1602 
1603 string t_doc_generator::find_obj_table_name(const vector<t_field*> members) {
1604  string obj_table_name;
1605  vector<t_field*>::const_iterator m_iter;
1606  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1607  map<string, string>::iterator jt;
1608  if((*m_iter)->get_name() == "name") {
1609  jt = (*m_iter)->annotations_.find("key");
1610  if (jt != (*m_iter)->annotations_.end()) {
1611  return (*m_iter)->annotations_["key"];
1612  }
1613  }
1614  }
1615  return obj_table_name;
1616 }
1617 
1618 template <typename T>
1619 void t_doc_generator::find_recursive_tags_map(T* tsandesh, t_field* tfield, string table, t_type* keytype, t_type* valtype, string prefix, vector<string>& schemas) {
1620  if (valtype->is_struct()) {
1621  string sname = valtype->get_name();
1622  find_recursive_tags_struct(tsandesh, tfield, table, sname, prefix, schemas);
1623  }
1624 }
1625 
1626 template <typename T>
1627 void t_doc_generator::find_recursive_tags_list(T* tsandesh, t_field* tfield, string table, t_type* ttype, string prefix, vector<string>& schemas) {
1628  if (ttype->is_struct()) {
1629  string sname = ttype->get_name();
1630  find_recursive_tags_struct(tsandesh, tfield, table, sname, prefix, schemas);
1631  }
1632 }
1633 
1634 template <typename T>
1635 void t_doc_generator::find_recursive_tags_struct(T* tsandesh, t_field* tfield, string table, string sname, string prefix, vector<string>& schemas) {
1636  t_struct *cstruct = find_struct_with_name(sname);
1637  if(cstruct) {
1638  const vector<t_field*> members = cstruct->get_members();
1639  generate_stat_tables_schema(tsandesh, members, table, prefix, schemas);
1640  }
1641 }
1642 
1643 template <typename T>
1644 void t_doc_generator::find_recursive_tags(T* tsandesh, t_field* tfield, string table, string fname, vector<string>& index_schemas) {
1645  string tags;
1646  if (tfield->get_type()->is_list()) {
1647  t_type* ltype= ((t_list*)((tfield)->get_type()))->get_elem_type();
1648  find_recursive_tags_list(tsandesh, tfield, table, ltype, fname, index_schemas);
1649  } else if (tfield->get_type()->is_map()) {
1650  t_type* keytype= ((t_map*)(tfield->get_type()))->get_key_type();
1651  t_type* valtype= ((t_map*)(tfield->get_type()))->get_val_type();
1652  find_recursive_tags_map(tsandesh, tfield, table, keytype, valtype, fname, index_schemas);
1653  } else if (tfield->get_type()->is_struct()) {
1654  string sname = (tfield->get_type())->get_name();
1655  find_recursive_tags_struct(tsandesh, tfield, table, sname, fname, index_schemas);
1656  }
1657 
1658 }
1659 
1661  string doc = tfield->get_doc();
1662  size_t index;
1663  string display_name;
1664  if ((index = doc.find_first_of("@")) != string::npos) {
1665  boost::char_separator<char> fsep("@");
1666  tokenizer ftokens(doc, fsep);
1667  BOOST_FOREACH(const string &f, ftokens) {
1668  size_t lindex;
1669  if ((lindex = f.find_first_of(": \t")) != string::npos) {
1670  string attr_name = f.substr(0, lindex);
1671  boost::trim(attr_name);
1672  if(attr_name == "display_name") {
1673  string dn = f.substr(lindex+1);
1674  display_name = dn.substr(0, dn.find_first_of('\n'));
1675  boost::trim(display_name);
1676  return display_name;
1677  }
1678  }
1679  }
1680  }
1681  return display_name;
1682 }
1683 
1684 template <typename T>
1685 void t_doc_generator::generate_stat_tables_schema(T* tsandesh, const vector<t_field*> members, string table, string prefix, vector<string>& tags) {
1686  vector<t_field*>::const_iterator m_iter;
1687  string oname = tsandesh->get_name();
1688  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1689  map<string, string>::iterator jt;
1690  jt = (*m_iter)->annotations_.find("tags");
1691  if (jt != (*m_iter)->annotations_.end()) {
1692  string fname = (*m_iter)->get_name();
1693  if (!prefix.empty())
1694  fname = prefix + "." + fname;
1695  string display_name = get_display_name_from_comments(*m_iter);
1696  generate_stat_table_schema_header(oname, fname, table, display_name);
1697  vector<string> new_tags;
1698  generate_stat_table_schema(oname, *m_iter, tsandesh, prefix, new_tags);
1699  for (int i = 0; i < tags.size(); i++) {
1700  if (tags[i][0] != ',')
1701  f_stats_tables_ << "," << endl;
1702  indent_up();
1703  indent(f_stats_tables_) << tags[i];
1704  indent_down();
1705  }
1706  f_stats_tables_ << "\n]\n}";
1707  find_recursive_tags(tsandesh, *m_iter, table, fname, new_tags);
1708  }
1709  }
1710 }
1711 
1713  bool is_uve = ((t_base_type *)tsandesh->get_type())->is_sandesh_uve();
1714  const vector<t_field*> members = tsandesh->get_members();
1715  string empty_prefix;
1716  vector<string> empty_tag;
1717  if (is_uve) {
1718  t_struct* data = program_->get_struct(members.front()->get_type()->get_name().c_str());
1719  const vector<t_field*> tmembers = data->get_members();
1720  string obj_table_name = find_obj_table_name(tmembers);
1721  generate_stat_tables_schema(data, tmembers, obj_table_name, empty_prefix, empty_tag);
1722  } else {
1723  string obj_table_name = "NONE";
1724  generate_stat_tables_schema(tsandesh, members, obj_table_name, empty_prefix, empty_tag);
1725  }
1726 }
1727 
1733 void t_doc_generator::generate_struct_table(t_struct* tstruct, ofstream &f_out) {
1734  vector<t_field*> members = tstruct->get_members();
1735  vector<t_field*>::iterator mem_iter = members.begin();
1736  f_out << "<table>";
1737  f_out << "<tr><th>Key</th><th>Field</th><th>Type</th><th>Description</th><th>Requiredness</th><th>Default value</th></tr>"
1738  << endl;
1739  for ( ; mem_iter != members.end(); mem_iter++) {
1740  f_out << "<tr><td>" << (*mem_iter)->get_key() << "</td><td>";
1741  f_out << (*mem_iter)->get_name();
1742  f_out << "</td><td>";
1743  print_type((*mem_iter)->get_type(), f_out);
1744  f_out << "</td><td>";
1745  f_out << (*mem_iter)->get_doc();
1746  f_out << "</td><td>";
1747  if ((*mem_iter)->get_req() == t_field::T_OPTIONAL) {
1748  f_out << "optional";
1749  } else if ((*mem_iter)->get_req() == t_field::T_REQUIRED) {
1750  f_out << "required";
1751  } else {
1752  f_out << "default";
1753  }
1754  f_out << "</td><td>";
1755  t_const_value* default_val = (*mem_iter)->get_value();
1756  if (default_val != NULL) {
1757  print_const_value(default_val, f_out);
1758  }
1759  f_out << "</td></tr>" << endl;
1760  }
1761  f_out << "</table><br/>";
1762 }
1763 
1769 void t_doc_generator::generate_struct(t_struct* tstruct, ofstream &f_out) {
1770  string name = tstruct->get_name();
1771  f_out << "<div class=\"definition\">";
1772  f_out << "<h3 id=\"Struct_" << name << "\">";
1773  f_out << "Struct: ";
1774  f_out << name << "</h3>" << endl;
1775  generate_struct_table(tstruct, f_out);
1776  print_doc(tstruct, f_out);
1777  f_out << "</div>";
1778 }
1779 
1780 bool t_doc_generator::generate_introspect_cli(t_sandesh* tsandesh, ofstream &f_out, bool &first_file) {
1781  if (tsandesh->has_doc()) {
1782  string doc = tsandesh->get_doc();
1783  size_t index;
1784  string cli_name = "", cli_help = "";
1785  if ((index = doc.find_first_of("@")) != string::npos) {
1786  string fdoc(doc.substr(index + 1));
1787  // Extract tokens beginning with @
1788  boost::char_separator<char> fsep("@");
1789  tokenizer ftokens(fdoc, fsep);
1790  BOOST_FOREACH(const string &f, ftokens) {
1791  // Has 2 parts, the first ending with ':' or ' ' or '\t' is
1792  // the type and the next is the content
1793  size_t lindex;
1794  if ((lindex = f.find_first_of(": \t")) != string::npos) {
1795  string type(f.substr(0, lindex));
1796  if (lindex + 1 < f.size() && f.at(lindex) != f.at(lindex + 1) &&
1797  (f.at(lindex + 1) == ':' || f.at(lindex + 1) == '\t' ||
1798  f.at(lindex + 1) == ' ')) {
1799  lindex++;
1800  }
1801  string content(f.substr(lindex + 1));
1802  content.erase(content.length()-1);
1803  if (boost::starts_with(type, "cli_name")) {
1804  cli_name = content;
1805  } else if (boost::starts_with(type, "description")) {
1806  cli_help = content;
1807  }
1808  }
1809  }
1810  }
1811  if (cli_name == "")
1812  return false;
1813  if (!first_file) {
1814  f_out << "," << endl;
1815  } else {
1816  first_file = false;
1817  }
1818 
1819  indent_up();
1820  indent(f_out) << "\"" << tsandesh->get_name() << "\" : {" << endl;
1821  indent(f_out) << "\"" << cli_name << "\" : " << "{ \"" << cli_help << "\" :" << endl;
1822  vector<t_field*> members = tsandesh->get_members();
1823  int size = members.size();
1824  int count = 0;
1825  indent(f_out) << "[ " << endl;
1826  indent_up();
1827  BOOST_FOREACH(t_field *tfield, members) {
1828  indent(f_out) << "[\"" << tfield->get_name();
1829  string field_doc = "\"\"";
1830  if (!tfield->get_doc().empty()) {
1831  field_doc = tfield->get_doc();
1832  field_doc.erase(field_doc.length()-1);
1833  field_doc = "\""+field_doc+"\"";
1834  }
1835  f_out << "\", " << field_doc << "]";
1836  count++;
1837  if (count < size)
1838  f_out << ",";
1839  f_out << endl;
1840  }
1841  indent_down();
1842  indent(f_out) << "]}}";
1843  indent_down();
1844  return true;
1845  }
1846  return false;
1847 }
1848 
1854 void t_doc_generator::generate_sandesh(t_sandesh* tsandesh, ofstream &f_out) {
1855  f_out << "<h3 id=\"Snh_" << sandesh_name_ << "\"> "
1856  << sandesh_name_ << "</h3>" << endl;
1857  print_sandesh(tsandesh, f_out);
1858  vector<t_field*> members = tsandesh->get_members();
1859  f_out << "<table>";
1860  f_out << "<tr><th>Field</th><th>Type</th><th>Description</th></tr>"
1861  << endl;
1862  BOOST_FOREACH(t_field *tfield, members) {
1863  if (tfield->get_auto_generated()) {
1864  continue;
1865  }
1866  t_type *type = tfield->get_type();
1867  if (type->is_static_const_string()) {
1868  continue;
1869  }
1870  f_out << "<tr><td>" << tfield->get_name() << "</td><td>";
1871  print_type(tfield->get_type(), f_out);
1872  f_out << "</td><td>";
1873  f_out << tfield->get_doc();
1874  f_out << "</td></tr>" << endl;
1875  }
1876  f_out << "</table><br/>";
1877 }
1878 
1884 void t_doc_generator::generate_sandesh_uve(t_sandesh* tsandesh, ofstream &f_out) {
1885  vector<t_field*> smembers = tsandesh->get_members();
1886  if (smembers.size() == 1 && smembers[0]->get_type()->is_struct()) {
1887  sandesh_name_ = smembers[0]->get_type()->get_name();
1888  boost::trim(sandesh_name_);
1889  f_out << "<h3 id=\"Snh_" << sandesh_name_ << "\"> "
1890  << sandesh_name_ << "</h3>" << endl;
1891  print_sandesh(tsandesh, f_out);
1892  t_struct *cstruct = find_struct_with_name(sandesh_name_);
1893  if (!cstruct) {
1894  f_out << "</table><br/>";
1895  return;
1896  }
1897  generate_struct_table(cstruct, f_out);
1898  }
1899 }
1900 
1901 THRIFT_REGISTER_GENERATOR(doc, "Documentation", "")
t_doc_generator(t_program *program, const map< string, string > &parsed_options, const string &option_string)
void generate_struct(t_struct *tstruct)
void find_recursive_tags_list(T *, t_field *, string, t_type *, string, vector< string > &)
void generate_stat_schema_struct_members(string name, t_field *, t_struct *, vector< string >, map< string, vector< string > >, vector< string > &)
virtual bool is_xception() const
Definition: t_type.h:74
const std::string & get_name() const
Definition: t_field.h:95
void print_doc_string(string doc, ofstream &f_out)
void init()
Definition: bgp_log.cc:37
t_type * get_type() const
Definition: t_typedef.h:42
string get_uve_type(string, t_field *)
Definition: t_enum.h:30
bool has_doc()
Definition: t_doc.h:41
string generate_stat_schema_struct_base_member(string, t_field *, string, t_field *)
void find_recursive_tags_struct(T *, t_field *, string, string, string, vector< string > &)
void print_sandesh(t_sandesh *tdoc, ofstream &f_out)
void generate_stat_table_schema_header(string, string, string, string)
void generate_stat_schema_map(string, t_type *, t_type *, t_field *, T *, bool, bool, vector< string > &)
Definition: t_type.h:48
void generate_stat_tables_schema(t_sandesh *)
void generate_service(t_service *tservice)
void is_indexed_or_suffixed_field(string, vector< string >, map< string, vector< string > >, string &, bool &, bool &)
void print_sandesh_message(t_sandesh *tdoc, ofstream &f_out)
string get_doc_file_description(doc_ftype::type dtype)
bool generate_introspect_cli(t_sandesh *, ofstream &f_out, bool &first_file)
virtual bool is_map() const
Definition: t_type.h:78
const std::string & get_name() const
Definition: t_program.h:92
string get_display_name_from_comments(t_field *)
void generate_sandesh_program_doc_schema_uve(t_program *tprog, ofstream &f_out, string fsuffix)
void print_const_value(t_const_value *tvalue, ofstream &f_out)
void generate_sandesh(t_sandesh *tsandesh)
virtual bool is_enum() const
Definition: t_type.h:72
t_type * get_type() const
Definition: t_field.h:91
virtual bool is_base_type() const
Definition: t_type.h:61
void generate_struct_table(t_struct *tstruct, ofstream &f_out)
t_struct * find_struct_with_name(string sname)
void generate_stat_schema_struct(string, t_field *, t_struct *, T *, bool, vector< string > &)
bool generate_sandesh_program(doc_ftype::type dtype)
void find_recursive_tags_map(T *, t_field *, string, t_type *, t_type *, string, vector< string > &)
void generate_stat_schema_suffixes(string, t_field *, t_struct *, T *, map< string, vector< string > > &, vector< string > &)
const std::map< t_const_value *, t_const_value * > & get_map() const
const members_type & get_members()
void generate_stats_schema_program()
string get_doc_member(t_sandesh *tsandesh, string member)
int64_t get_integer() const
Definition: t_const_value.h:72
void generate_doc_type(ofstream &f_out)
t_const_value_type get_type() const
string get_datatype_from_tfield(t_type *tfield)
virtual bool is_container() const
Definition: t_type.h:75
virtual bool is_typedef() const
Definition: t_type.h:71
t_type * get_type() const
Definition: t_const.h:40
#define MKDIR(x)
Definition: platform.h:28
uint8_t type
Definition: load_balance.h:109
void generate_enum(t_enum *tenum)
Definition: t_doc.h:27
virtual bool is_set() const
Definition: t_type.h:77
std::string get_name() const
Definition: t_const.h:44
string get_object_type(t_sandesh *tsandesh)
boost::tokenizer< boost::char_separator< char > > tokenizer
t_const_value * get_value() const
Definition: t_const.h:48
void generate_sandesh_uve(t_sandesh *tsandesh, ofstream &f_out)
void generate_consts(vector< t_const * > consts, ofstream &f_out)
string sandesh_level_to_string(const sandesh_level::type &slevel)
string get_type_of_member(string, t_field *, t_struct *, T *)
virtual const std::string & get_name() const
Definition: t_type.h:56
Definition: t_map.h:30
virtual bool is_list() const
Definition: t_type.h:76
void generate_const_enum_typedef_object_program()
const std::vector< t_enum_value * > & get_constants()
Definition: t_enum.h:43
void generate_typedef(t_typedef *ttypedef)
void print_doc(t_doc *tdoc, ofstream &f_out)
double get_double() const
Definition: t_const_value.h:99
void generate_program_toc(ofstream &f_out, string fsuffix, doc_ftype::type dtype)
t_program * get_program()
Definition: t_type.h:81
virtual bool is_struct() const
Definition: t_type.h:73
void generate_const(t_const *tconst)
Definition: t_set.h:29
sandesh_level::type get_sandesh_level(t_sandesh *tsandesh)
const std::string & get_doc() const
Definition: t_doc.h:37
const t_type * get_type()
Definition: t_sandesh.h:71
void extract_tags(T *, map< string, vector< string > > &, vector< string > &, vector< string > &)
bool is_sandesh_type(t_sandesh *tsandesh, doc_ftype::type dtype)
Definition: t_list.h:29
string get_doc_file_suffix(doc_ftype::type dtype)
string generate_table_entry(string name, string datatype, string index, string)
void generate_stat_table_schema(string, t_field *, T *, string, vector< string > &)
void find_recursive_tags(T *, t_field *, string, string, vector< string > &)
int print_type(t_type *ttype, ofstream &f_out)
bool generate_sandesh_program_doc(t_program *tprog, ofstream &f_out, string fsuffix, doc_ftype::type dtype)
t_const_value * get_value()
Definition: t_field.h:121
void generate_sandesh_program_doc_schema(t_program *tprog, ofstream &f_out, string fsuffix, doc_ftype::type dtype)
string find_obj_table_name(const vector< t_field * >)
void generate_stat_schema_list(string, t_type *, t_field *, T *, bool, bool, vector< string > &)
std::map< std::string, std::string > annotations_
Definition: t_field.h:199
virtual bool is_service() const
Definition: t_type.h:79
void print_sandesh_message_table(t_sandesh *tdoc, ofstream &f_out)
void generate_program_toc_row(t_program *tprog, ofstream &f_out, string fsuffix, doc_ftype::type dtype)
#define THRIFT_REGISTER_GENERATOR(language, long_name, doc)
void generate_stat_schema_toplevel_tags(T *, vector< string > &, vector< string > &, t_field *)
sandesh_level::type string_to_sandesh_level(const string &level)
const std::vector< t_const_value * > & get_list() const
ofstream f_stats_tables_