1 //@copyright_begin
2 // ================================================================
3 // Copyright Notice
4 // Copyright (C) 1998-2004 by Joe Linoff
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the
8 // "Software"), to deal in the Software without restriction, including
9 // without limitation the rights to use, copy, modify, merge, publish,
10 // distribute, sublicense, and/or sell copies of the Software, and to
11 // permit persons to whom the Software is furnished to do so, subject to
12 // the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 // IN NO EVENT SHALL JOE LINOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 // OTHER DEALINGS IN THE SOFTWARE.
24 //
25 // Comments and suggestions are always welcome.
26 // Please report bugs to http://ccdoc.sourceforge.net/ccdoc
27 // ================================================================
28 //@copyright_end
29 #if defined(_MSC_VER)
30 #pragma warning ( disable : 4786 4251 )
31 #endif
32
33 #include <cassert>
34 #include <cstdio>
35 #include <cstring>
36 #include <algorithm>
37 #include <iomanip>
38 #include "exceptions.h"
39 #include "phase3_html.h"
40
41 // ================================================================
42 // This variable allows the header version
43 // to be queried at runtime.
44 // ================================================================
45 namespace {
46 char ccdoc_rcsid[] = "$Id: phase3_html.cc,v 1.18 2004/09/30 16:09:27 jlinoff Exp $";
47 }
48
49 // ================================================================
50 // Forward declarations for sort compare functions.
51 // ================================================================
52 namespace
53 {
54 bool compare_stmts_full_paths(const ccdoc::statement::base* a,
55 const ccdoc::statement::base* b);
56 bool compare_stmts(const ccdoc::statement::base* a,
57 const ccdoc::statement::base* b);
58 }
59 // ================================================================
60 // Html
61 // ================================================================
html(switches & sw,database & db)62 ccdoc::phase3::html::html(switches& sw,database& db)
63 : m_debug(false),
64 m_ok(false),
65 m_db(db),
66 m_sw(sw),
67 m_multiple_ref_index(0)
68 {
69 }
70 // ================================================================
71 // Html
72 // ================================================================
~html()73 ccdoc::phase3::html::~html() {
74 }
75 // ================================================================
76 // Run
77 // ================================================================
run()78 bool ccdoc::phase3::html::run()
79 {
80 // Load the customized header and trailer stuff.
81 load(m_sw.header(),m_header);
82 load(m_sw.trailer(),m_trailer);
83 load(m_sw.meta(),m_meta);
84
85 m_db.clear_path_map();
86 m_db.load_path_map(); // Issue 0039
87
88 // Issue 0044
89 // Allow the user to control the hierarchical indent level.
90 {
91 m_rptcsi = "";
92 for(int i=m_sw.rptcsi();i>0;--i) {
93 m_rptcsi += " ";
94 }
95 }
96
97 write_ccdoc_pkgs_html();
98 write_ccdoc_namespaces_html();
99 write_ccdoc_classes_html();
100 write_ccdoc_class_summary_html();
101 write_ccdoc_functions_html();
102 write_ccdoc_variables_html();
103 write_ccdoc_enums_html();
104 write_ccdoc_typedefs_html();
105 write_ccdoc_macros_html();
106
107 m_ok = true;
108 return m_ok;
109 }
110 // ================================================================
111 // Write the package files.
112 // Each package file contains the following:
113 // - The ccdoc description section.
114 // - The table of contents: child packages and namespaces.
115 // ================================================================
write_ccdoc_pkgs_html()116 void ccdoc::phase3::html::write_ccdoc_pkgs_html()
117 {
118 statement::base::stmts_t stmts;
119 m_db.load(stmts,statement::base::STMT_PACKAGE);
120 if( m_sw.verbose() ) {
121 s_log << "phase3: generating HTML for "
122 << stmts.size()
123 << " packages ...\n";
124 }
125
126 statement::base::stmts_itr_t itr = stmts.begin();
127 for(;itr!=stmts.end();++itr) {
128 string fn;
129 statement::base* stmt = *itr;
130 make_unique_file_name(fn,stmt);
131 ofstream os(fn.c_str());
132 if(!os) {
133 throw ccdoc::exceptions::unwriteable_output_file(__FILE__,
134 __LINE__,
135 fn.c_str());
136 }
137 if( m_sw.verbose() ) {
138 string hier_id;
139 stmt->get_hier_id(hier_id);
140 s_log << "phase3: generating HTML for package "
141 << hier_id
142 << " ...\n";
143 }
144 write_common_header_info(os,fn,stmt);
145 write_section_header(os,stmt,true);
146 write_indent(os);
147 write_ccdoc_info(os,stmt,m_sw.rptdpa(),m_sw.rptdpv());
148 write_unindent(os);
149 write_contents(os,stmt);
150 write_common_trailer_info(os);
151 }
152 }
153 // ================================================================
154 // write the namespace files.
155 // Each namespace file contains the following:
156 // - The ccdoc description section.
157 // - The table of contents: child namespaces.
158 // ================================================================
write_ccdoc_namespaces_html()159 void ccdoc::phase3::html::write_ccdoc_namespaces_html()
160 {
161 statement::base::stmts_t stmts;
162 m_db.load(stmts,statement::base::STMT_NAMESPACE_BEGIN);
163 if( m_sw.verbose() ) {
164 s_log << "phase3: generating HTML for "
165 << stmts.size()
166 << " namespaces ...\n";
167 }
168 statement::base::stmts_itr_t itr = stmts.begin();
169 for(;itr!=stmts.end();++itr) {
170 string fn;
171 statement::base* stmt = *itr;
172
173 // Skip the internal ids of the form:
174 // +<name>+<file>:<line>
175 // that are used store the comments
176 // until they can be extracted here
177 // by chaining using the get_next()
178 // method that is set in phase3.
179 // They are artifacts.
180 if( ignore_contents_stmt(stmt) ) {
181 if( m_sw.verbose() ) {
182 string hier_id;
183 stmt->get_hier_id(hier_id);
184 s_log << "phase3: skipping HTML for internal namespace "
185 << hier_id
186 << " ...\n";
187 }
188 continue;
189 }
190
191 make_unique_file_name(fn,stmt);
192 ofstream os(fn.c_str());
193 if(!os) {
194 throw ccdoc::exceptions::unwriteable_output_file(__FILE__,
195 __LINE__,
196 fn.c_str());
197 }
198 if( m_sw.verbose() ) {
199 string hier_id;
200 stmt->get_hier_id(hier_id);
201 s_log << "phase3: generating HTML for namespace "
202 << hier_id
203 << " ...\n";
204 }
205 write_common_header_info(os,fn,stmt);
206 write_section_header(os,stmt,true);
207 write_indent(os);
208 write_ccdoc_info(os,stmt,true,true);
209
210 // Issue 0133
211 // Special case handling for comment chains.
212 // These occur in namespaces where multiple sets
213 // of comments are chained together. These are
214 // handled by walking through the chains and
215 // output the comments in an indented form with
216 // a separator for each one.
217 if( stmt->get_next() ) {
218 statement::base* chain = stmt->get_next();
219 for(;chain;chain = chain->get_next()) {
220 if( !m_sw.rptcfuns() && !chain->get_comment() ) {
221 // Don't report namespaces with empty comments.
222 continue;
223 }
224 os << "<table border=1 width=\"90%\">\n";
225 os << "<tr>\n";
226 os << "<td>\n";
227 os << "<b>"
228 << chain->get_file() << ":"
229 << chain->get_lineno() << "</b>\n";
230 os << "<blockquote>\n";
231 write_ccdoc_info(os,chain,true,true);
232 os << "</blockquote>\n";
233 os << "</td>\n";
234 os << "</tr>\n";
235 os << "</table>\n";
236 }
237 }
238
239 write_unindent(os);
240 write_contents(os,stmt);
241 write_common_trailer_info(os);
242 }
243 }
244 // ================================================================
245 // write the class files.
246 // ================================================================
write_ccdoc_classes_html()247 void ccdoc::phase3::html::write_ccdoc_classes_html()
248 {
249 statement::base::stmts_t stmts;
250 m_db.load(stmts,statement::base::STMT_CLASS_BEGIN);
251 m_db.load(stmts,statement::base::STMT_STRUCT_BEGIN);
252 if( m_sw.rptun() ) {
253 m_db.load(stmts,statement::base::STMT_UNION_BEGIN);
254 }
255 statement::base::stmts_itr_t itr = stmts.begin();
256 if( m_sw.verbose() ) {
257 s_log << "phase3: generating HTML for "
258 << stmts.size()
259 << " classes ...\n";
260 }
261 for(;itr!=stmts.end();++itr) {
262 string fn;
263 statement::base* stmt = *itr;
264 make_unique_file_name(fn,stmt);
265 ofstream os(fn.c_str());
266 if(!os) {
267 throw ccdoc::exceptions::unwriteable_output_file(__FILE__,
268 __LINE__,
269 fn.c_str());
270 }
271 if( m_sw.verbose() ) {
272 string hier_id;
273 stmt->get_hier_id(hier_id);
274 s_log << "phase3: generating HTML for class "
275 << hier_id
276 << " ...\n";
277 }
278 write_common_header_info(os,fn,stmt);
279 write_section_header(os,stmt,true);
280 write_extends_clause(os,stmt);
281 write_indent(os);
282 write_ccdoc_info(os,stmt,true,true);
283 write_friends_info(os,stmt);
284 write_unindent(os);
285 write_contents(os,stmt,m_sw.rptsci());
286 write_class_details(os,stmt,m_sw.rptsci());
287 write_common_trailer_info(os);
288 }
289 }
290 // ================================================================
291 // Generating the class summary.
292 // ================================================================
write_ccdoc_class_summary_html()293 void ccdoc::phase3::html::write_ccdoc_class_summary_html()
294 {
295 statement::base::stmts_t stmts;
296 m_db.load(stmts,statement::base::STMT_CLASS_BEGIN);
297 m_db.load(stmts,statement::base::STMT_STRUCT_BEGIN);
298 if( m_sw.verbose() ) {
299 s_log << "phase3: generating HTML for class summary\n";
300 }
301
302 // Open the HTML file.
303 string fn;
304 fn = m_sw.html() + "ccdoc.class_summary.html";
305 ofstream os(fn.c_str());
306 if(!os) {
307 throw ccdoc::exceptions::unwriteable_output_file(__FILE__,
308 __LINE__,
309 fn.c_str());
310 }
311 write_common_header_info(os,fn,"Class Summary");
312 os << "<table border=0 width=\"100%\"><tr><td align=left>";
313 if( m_sw.rooturl().size() ) {
314 os << "<a href=\"" << m_sw.rooturl() << "\" target=_top>Home</a>";
315 os << " :: ";
316 }
317 write_link(os,m_db.root());
318 os << "</td><td align=right>";
319 string url;
320 string link_name = m_sw.html() + "ccdoc.class_summary.html";
321 make_file_url(url,link_name);
322 os << "<a href=\"" << url << "\">classes</a></td></tr></table>\n";
323
324 write_section_header(os,"Class Summary",false);
325 write_summary_tree(os,stmts,m_sw.rptcsd(),0,m_rptcsi.c_str());
326 write_common_trailer_info(os);
327 }
328 // ================================================================
329 // Generating the class summary.
330 // ================================================================
write_summary_tree(ostream & os,statement::base::stmts_t & stmts,bool rpthpc,statement::base * start,const char * in_indent,bool sort_flag)331 void ccdoc::phase3::html::write_summary_tree(ostream& os,
332 statement::base::stmts_t& stmts,
333 bool rpthpc,
334 statement::base* start,
335 const char* in_indent,
336 bool sort_flag)
337 {
338 // ================================================
339 // Order the entries.
340 // ================================================
341 if( sort_flag ) {
342 stable_sort(stmts.begin(),stmts.end(),compare_stmts_full_paths);
343 }
344
345 // ================================================
346 // Initialize the tags.
347 // These are used later to identify when the parents
348 // have been visited.
349 // ================================================
350 statement::base::stmts_itr_t itr = stmts.begin();
351 for(;itr!=stmts.end();++itr) {
352 statement::base* stmt = *itr;
353 stmt->set_tag(0);
354 statement::base::stmts_t parents;
355 stmt->get_parents(parents);
356 statement::base::stmts_itr_t pitr = parents.begin();
357 for(;pitr!=parents.end();++pitr) {
358 statement::base* parent = *pitr;
359 parent->set_tag(0);
360 }
361 }
362
363 // ================================================
364 // Output the information.
365 // ================================================
366 if( stmts.size() == 0 )
367 return;
368 if( rpthpc ) {
369 // Issue 0026
370 os << "<table border=0>\n"
371 << "<tr>"
372 << "<th valign=bottom align=left>Entity</th>"
373 << "<th valign=bottom align=left>Type</th>"
374 << "<th valign=bottom align=left>Scope</th>";
375 if( m_sw.rptsrc() ) {
376 os << "<th valign=bottom align=left>Source</th>";
377 }
378 os << "<th valign=bottom align=left>Short Description</th>"
379 << "</tr>\n";
380 }
381 else {
382 os << "<table border=0 cellpadding=0 cellspacing=0>\n";
383 }
384 itr = stmts.begin();
385 for(;itr!=stmts.end();++itr) {
386 statement::base* stmt = *itr;
387 if( stmt->get_tag() == 0 ) {
388 string indent = "";
389 statement::base::stmts_t parents;
390 stmt->get_parents(parents);
391 statement::base::stmts_itr_t pitr = parents.begin();
392 if( start ) {
393 // The start parent was specified,
394 // skip ahead until a match is found.
395 for(;pitr!=parents.end();++pitr) {
396 statement::base* parent = *pitr;
397 if( parent == start ) {
398 ++pitr;
399 break;
400 }
401 }
402 }
403 for(;pitr!=parents.end();++pitr) {
404 statement::base* parent = *pitr;
405 if( parent->get_tag() == 0 ) {
406 parent->set_tag(1);
407 pitr = parents.begin();
408 write_summary_tree_entry(os,parent,indent.c_str(),rpthpc);
409 indent = "";
410 }
411 indent += in_indent;
412 }
413 stmt->set_tag(1);
414 write_summary_tree_entry(os,stmt,indent.c_str(),rpthpc);
415 }
416 }
417 os << "</table>\n";
418 }
419 // ================================================================
420 // Generating the class summary.
421 // ================================================================
write_summary_tree_entry(ostream & os,statement::base * stmt,const char * indent,bool rpthpc)422 void ccdoc::phase3::html::write_summary_tree_entry(ostream& os,
423 statement::base* stmt,
424 const char* indent,
425 bool rpthpc)
426 {
427 os << "<tr>";
428
429 // Id
430 os << "<td align=left valign=top>";
431 if(indent)
432 os << indent;
433 if( stmt ) {
434 string id = stmt->get_id();
435 unsigned max_entity_size = m_sw.rptmlcei() + m_sw.rptmlcifi();
436 if( max_entity_size && id.size() > max_entity_size ) {
437 // Issue 0159:
438 // Truncate the id to the shorter number of characters
439 // and add the '..'.
440 string short_id = id.substr(0,max_entity_size);
441 short_id += "..";
442 write_link(os,stmt,short_id.c_str());
443 }
444 else {
445 write_link(os,stmt,id.c_str());
446 }
447 }
448 os << "</td>";
449
450 // Type
451 if( rpthpc ) {
452 // Issue 0026
453
454 // Type
455 string type = stmt->get_type_name2();
456 if( stmt->get_type() == statement::base::STMT_PACKAGE &&
457 stmt->get_comment() ) {
458 statement::comment doc(stmt->get_comment());
459 string tid = doc.get_pkgdoc_tid();
460 if( tid.size() )
461 type = tid;
462 }
463 os << "<td align=left valign=top>"
464 << type
465 << " </td>";
466
467 // Access
468 os << "<td align=left valign=top>";
469 os << stmt->get_access_name();
470 os << "</td>";
471
472 // Source info
473 if( m_sw.rptsrc() ) {
474 os << "<td align=left valign=top>";
475 os << stmt->get_file() << ":" << stmt->get_lineno();
476 os << "</td>";
477 }
478
479 // Short description
480 os << "<td align=left valign=top>";
481 write_short_desc(os,stmt);
482 os << "</td>";
483 }
484 os << "</tr>\n";
485 }
486 // ================================================================
487 // Generating the class summary.
488 // ================================================================
write_short_desc(ostream & os,statement::base * stmt)489 void ccdoc::phase3::html::write_short_desc(ostream& os,
490 statement::base* stmt)
491 {
492 if( stmt->get_comment() ) {
493 statement::comment doc(stmt->get_comment());
494 if( doc.get_short_desc().size() == 0 ) {
495 // Issue 0030
496 if( stmt->get_type() != statement::base::STMT_PACKAGE ||
497 m_sw.rptdpd() == false ) {
498 os << m_sw.rptdefsd();
499 }
500 }
501 else {
502 statement::base* scope = stmt->get_parent();
503 write_ccdoc_desc_info(os,doc.get_short_desc(),scope,stmt);
504 }
505 }
506 else {
507 if( stmt->get_lineno() == 0 ) {
508 // Lineno zero flags the fact that it
509 // was automatically generated by the
510 // compiler.
511 os << m_sw.rptdefasd();
512 }
513 else {
514 // Issue 0030
515 if( stmt->get_type() != statement::base::STMT_PACKAGE ||
516 m_sw.rptdpd() == false ) {
517 os << m_sw.rptdefsd();
518 }
519 }
520 }
521 }
522 // ================================================================
523 // write the function files.
524 // ================================================================
write_ccdoc_functions_html()525 void ccdoc::phase3::html::write_ccdoc_functions_html()
526 {
527 statement::base::stmts_t stmts;
528 m_db.load_top(stmts,statement::base::STMT_FUNCTION);
529 m_db.load_top(stmts,statement::base::STMT_FUNCTION_OPERATOR);
530 if( m_sw.verbose() ) {
531 s_log << "phase3: generating HTML for "
532 << stmts.size()
533 << " global functions ...\n";
534 }
535 statement::base::stmts_itr_t itr = stmts.begin();
536 for(;itr!=stmts.end();++itr) {
537 string fn;
538 statement::base* stmt = *itr;
539 make_unique_file_name(fn,stmt);
540 ofstream os(fn.c_str());
541 if(!os) {
542 throw ccdoc::exceptions::unwriteable_output_file(__FILE__,
543 __LINE__,
544 fn.c_str());
545 }
546 if( m_sw.verbose() ) {
547 string hier_id;
548 stmt->get_hier_id(hier_id);
549 s_log << "phase3: generating HTML for global function "
550 << hier_id
551 << " ...\n";
552 }
553 write_common_header_info(os,fn,stmt);
554 write_section_header(os,stmt,false);
555 write_indent(os);
556 write_ccdoc_info(os,stmt,true,true);
557 write_code_section(os,stmt);
558 write_unindent(os);
559 write_common_trailer_info(os);
560 }
561 }
562 // ================================================================
563 // write the variable files.
564 // ================================================================
write_ccdoc_variables_html()565 void ccdoc::phase3::html::write_ccdoc_variables_html()
566 {
567 statement::base::stmts_t stmts;
568 m_db.load_top(stmts,statement::base::STMT_ATTRIBUTE);
569 m_db.load_top(stmts,statement::base::STMT_ATTRIBUTE_FUNCTION);
570 m_db.load_top(stmts,statement::base::STMT_VARIABLE);
571 m_db.load_top(stmts,statement::base::STMT_VARIABLE_FUNCTION);
572 statement::base::stmts_itr_t itr = stmts.begin();
573 if( m_sw.verbose() ) {
574 s_log << "phase3: generating HTML for "
575 << stmts.size()
576 << " global variables ...\n";
577 }
578 for(;itr!=stmts.end();++itr) {
579 string fn;
580 statement::base* stmt = *itr;
581 make_unique_file_name(fn,stmt);
582 ofstream os(fn.c_str());
583 if(!os) {
584 throw ccdoc::exceptions::unwriteable_output_file(__FILE__,
585 __LINE__,
586 fn.c_str());
587 }
588 if( m_sw.verbose() ) {
589 string hier_id;
590 stmt->get_hier_id(hier_id);
591 s_log << "phase3: generating HTML for global variable "
592 << hier_id
593 << " ...\n";
594 }
595 write_common_header_info(os,fn,stmt);
596 write_section_header(os,stmt,false);
597 write_indent(os);
598 write_ccdoc_info(os,stmt,true,true);
599 write_code_section(os,stmt);
600 write_unindent(os);
601 write_common_trailer_info(os);
602 }
603 }
604 // ================================================================
605 // write the enum files.
606 // ================================================================
write_ccdoc_enums_html()607 void ccdoc::phase3::html::write_ccdoc_enums_html()
608 {
609 statement::base::stmts_t stmts;
610 m_db.load_top(stmts,statement::base::STMT_ENUM);
611 if( m_sw.verbose() ) {
612 s_log << "phase3: generating HTML for "
613 << stmts.size()
614 << " global enums ...\n";
615 }
616 statement::base::stmts_itr_t itr = stmts.begin();
617 for(;itr!=stmts.end();++itr) {
618 string fn;
619 statement::base* stmt = *itr;
620 make_unique_file_name(fn,stmt);
621 ofstream os(fn.c_str());
622 if(!os) {
623 throw ccdoc::exceptions::unwriteable_output_file(__FILE__,
624 __LINE__,
625 fn.c_str());
626 }
627 if( m_sw.verbose() ) {
628 string hier_id;
629 stmt->get_hier_id(hier_id);
630 s_log << "phase3: generating HTML for global enum "
631 << hier_id
632 << " ...\n";
633 }
634 write_common_header_info(os,fn,stmt);
635 write_section_header(os,stmt,false);
636 write_indent(os);
637 write_ccdoc_info(os,stmt,true,true);
638 write_code_section(os,stmt);
639 write_unindent(os);
640 write_common_trailer_info(os);
641 }
642 }
643 // ================================================================
644 // write the typedef files.
645 // ================================================================
write_ccdoc_typedefs_html()646 void ccdoc::phase3::html::write_ccdoc_typedefs_html()
647 {
648 if( m_sw.rpttyp() == false )
649 return;
650 statement::base::stmts_t stmts;
651 m_db.load_top(stmts,statement::base::STMT_TYPEDEF_FUNCTION);
652 m_db.load_top(stmts,statement::base::STMT_TYPEDEF_VARIABLE);
653 if( m_sw.verbose() ) {
654 s_log << "phase3: generating HTML for "
655 << stmts.size()
656 << " global typedefs ...\n";
657 }
658 statement::base::stmts_itr_t itr = stmts.begin();
659 for(;itr!=stmts.end();++itr) {
660 string fn;
661 statement::base* stmt = *itr;
662 make_unique_file_name(fn,stmt);
663 ofstream os(fn.c_str());
664 if(!os) {
665 throw ccdoc::exceptions::unwriteable_output_file(__FILE__,
666 __LINE__,
667 fn.c_str());
668 }
669 if( m_sw.verbose() ) {
670 string hier_id;
671 stmt->get_hier_id(hier_id);
672 s_log << "phase3: generating HTML for global typedef "
673 << hier_id
674 << " ...\n";
675 }
676 write_common_header_info(os,fn,stmt);
677 write_section_header(os,stmt,false);
678 write_indent(os);
679 write_ccdoc_info(os,stmt,true,true);
680 write_code_section(os,stmt);
681 write_unindent(os);
682 write_common_trailer_info(os);
683 }
684 }
685 // ================================================================
686 // write the macro files.
687 // ================================================================
write_ccdoc_macros_html()688 void ccdoc::phase3::html::write_ccdoc_macros_html()
689 {
690 if( !m_sw.rptmac() )
691 return;
692 statement::base::stmts_t stmts;
693 m_db.load_top(stmts,statement::base::STMT_MACRODEF_0_0);
694 m_db.load_top(stmts,statement::base::STMT_MACRODEF_0_1);
695 m_db.load_top(stmts,statement::base::STMT_MACRODEF_0_N);
696 m_db.load_top(stmts,statement::base::STMT_MACRODEF_N_N);
697 if( m_sw.verbose() ) {
698 s_log << "phase3: generating HTML for "
699 << stmts.size()
700 << " macro definitions ...\n";
701 }
702 statement::base::stmts_itr_t itr = stmts.begin();
703 for(;itr!=stmts.end();++itr) {
704 string fn;
705 statement::base* stmt = *itr;
706 make_unique_file_name(fn,stmt);
707 ofstream os(fn.c_str());
708 if(!os) {
709 throw ccdoc::exceptions::unwriteable_output_file(__FILE__,
710 __LINE__,
711 fn.c_str());
712 }
713 if( m_sw.verbose() ) {
714 string hier_id;
715 stmt->get_hier_id(hier_id);
716 s_log << "phase3: generating HTML for macro "
717 << hier_id
718 << " ...\n";
719 }
720 write_common_header_info(os,fn,stmt);
721 write_section_header(os,stmt,false);
722 write_indent(os);
723 write_ccdoc_info(os,stmt,true,true);
724 write_code_section(os,stmt);
725 write_unindent(os);
726 write_common_trailer_info(os);
727 }
728 }
729 // ================================================================
730 // Write the class details.
731 // ================================================================
write_class_details(ostream & os,statement::base * stmt,bool sort_flag)732 void ccdoc::phase3::html::write_class_details(ostream& os,
733 statement::base* stmt,
734 bool sort_flag)
735 {
736 if( stmt ) {
737 statement::base::stmts_t contents;
738 make_contents(stmt,contents,sort_flag);
739 string prev_tag;
740 string next_tag;
741 statement::base::stmts_itr_t next_itr;
742 statement::base::stmts_itr_t itr = contents.begin();
743 for(;itr!=contents.end();++itr) {
744 statement::base* child = *itr;
745 string tag;
746 make_tag_id(child,tag);
747 os << "<a name=\"" << tag << "\"></a>\n";
748
749 // Get the next tag.
750 next_itr = itr;
751 ++next_itr;
752 if( next_itr != contents.end() ) {
753 make_tag_id(*next_itr,next_tag);
754 }
755 write_section_header(os,
756 child,
757 true,
758 prev_tag.c_str(),
759 next_tag.c_str());
760 write_indent(os);
761 if( child->get_parent() == stmt ) {
762 write_ccdoc_info(os,child,false,false,false);
763 }
764 else {
765 write_ccdoc_info(os,child,false,false,true);
766 }
767 write_code_section(os,child);
768 write_unindent(os);
769 prev_tag = tag;
770 }
771 }
772 }
773 // ================================================================
774 // write contents
775 // ================================================================
write_contents(ostream & os,statement::base * stmt,bool sort_flag)776 void ccdoc::phase3::html::write_contents(ostream& os,
777 statement::base* stmt,
778 bool sort_flag)
779 {
780 bool inherited_from_col = false;
781 if( m_sw.rptim() ) {
782 if( stmt->get_type() == statement::base::STMT_CLASS_BEGIN ||
783 stmt->get_type() == statement::base::STMT_STRUCT_BEGIN ) {
784 // Don't create the inherited from column unless this
785 // class is derived.
786 int depth = 0;
787 const statement::base::cstrs_t& tokens = stmt->get_tokens();
788 statement::base::cstrs_citr_t itr = tokens.begin();
789 for(;itr!=tokens.end();++itr) {
790 string token = *itr;
791 if( token == "<" ) {
792 depth++;
793 }
794 else if( token == ">" ) {
795 depth--;
796 }
797 else if( depth == 0 && token == ":" ) {
798 inherited_from_col = true;
799 break;
800 }
801 }
802 }
803 }
804
805 if( m_sw.rpthpc() && stmt->get_type() == statement::base::STMT_PACKAGE ) {
806 os << "<a name=\"ccdoc_contents\"></a>\n";
807 write_section_header(os,"Contents",false);
808 write_indent(os);
809
810 statement::base::stmts_t unfiltered_contents;
811 statement::base::stmts_t filtered_contents;
812 stmt->get_all_children(unfiltered_contents);
813 statement::base::stmts_itr_t itr = unfiltered_contents.begin();
814 for(;itr!=unfiltered_contents.end();++itr) {
815 statement::base* child = *itr;
816 if(ignore_contents_stmt(child))
817 continue;
818 if( child->get_type() == statement::base::STMT_PACKAGE ) {
819 // Always report the nested packages.
820 filtered_contents.push_back(child);
821 }
822 else {
823 // Issue 0034
824 if( child->get_parent() == stmt )
825 filtered_contents.push_back(child);
826 }
827 }
828 // Issue 0047: -rptcsi also controls the contents column.
829 write_summary_tree(os,filtered_contents,true,stmt,m_rptcsi.c_str());
830 write_unindent(os);
831 return;
832 }
833 // ================================================
834 // This is the standard contents table.
835 // ================================================
836 statement::base::stmts_t contents;
837 make_contents(stmt,contents,sort_flag);
838 if( contents.size() ) {
839 os << "<a name=\"ccdoc_contents\"></a>\n";
840 write_section_header(os,"Contents",false);
841 write_indent(os);
842
843 os << "<table cellspacing=4>\n"
844 << "<tr>\n"
845 << "<th valign=bottom align=left>Entity</th>"; // Issue 0038
846
847 unsigned max_entity_size = m_sw.rptmlcei() + m_sw.rptmlcifi();
848 if( inherited_from_col ) {
849 os << "<th valign=bottom align=left>Inherited From</th>"; // Issue 0037
850 max_entity_size = m_sw.rptmlcei();
851 }
852
853 os << "<th valign=bottom align=left>Type</th>"
854 << "<th valign=bottom align=left>Scope</th>";
855
856 if( m_sw.rptsrc() ) {
857 os << "<th valign=bottom align=left>Source</th>";
858 }
859
860 os << "<th valign=bottom align=left>Short Description</th>"
861 << "</tr>\n";
862
863 statement::base::stmts_itr_t itr = contents.begin();
864 for(;itr!=contents.end();++itr) {
865 statement::base* child = *itr;
866 os << "<tr>\n";
867
868 // Write the id.
869 os << "<td align=left valign=top>";
870 if( child->get_type() == statement::base::STMT_PACKAGE ||
871 child->get_type() == statement::base::STMT_NAMESPACE_BEGIN ) {
872 string link;
873 if( stmt->get_parent() )
874 make_rel_path(stmt,child,link);
875 else
876 make_abs_path(child,link);
877 write_link(os,child,link.c_str());
878 }
879 else {
880 if( child->get_parent() == stmt ) {
881 string id = child->get_id();
882 if( max_entity_size && id.size() > max_entity_size ) {
883 // Issue 0159:
884 // Truncate the id to the shorter number of characters
885 // and add the '..'.
886 string short_id = id.substr(0,max_entity_size);
887 short_id += "..";
888 write_link(os,child,short_id.c_str());
889 }
890 else {
891 write_link(os,child,id.c_str());
892 }
893 }
894 else {
895 // These are children from other parents.
896 // They are created when derived classes
897 // inherit methods.
898 string url;
899 string id;
900 make_file_url(url,stmt);
901 make_tag_id(child,id);
902 //write_link(os,child->get_parent());
903 //os << " :: ";
904 os << "<a href=\"" << url << "#" << id << "\">";
905 id = child->get_id();
906 if( max_entity_size && id.size() > max_entity_size ) {
907 // Issue 0159:
908 // Truncate the id to the shorter number of characters
909 // and add the '..'.
910 string short_id = id.substr(0,max_entity_size);
911 short_id += "..";
912 write_html_formatted_string(os,short_id.c_str());
913 }
914 else {
915 write_html_formatted_string(os,id.c_str());
916 }
917 os << "</a>";
918 }
919 }
920 os << "</td>";
921
922 if( inherited_from_col ) {
923 os << "<td align=left valign=top>";
924 if( child->get_parent() && child->get_parent() != stmt ) {
925 string id;
926 child->get_parent()->get_hier_id_no_pkgs(id);
927 if( m_sw.rptmlcifi() && id.size() > m_sw.rptmlcifi() ) {
928 // Issue 0159:
929 // Truncate the id to the shorter number of characters
930 // and add the '..'.
931 string short_id = id.substr(0,m_sw.rptmlcifi());
932 short_id += "..";
933 write_link(os,child->get_parent(),short_id.c_str());
934 }
935 else {
936 write_link(os,child->get_parent(),id.c_str());
937 }
938 }
939 os << "</td>";
940 }
941
942 // Type
943 string type = child->get_type_name2(); // include static
944 if( child->get_type() == statement::base::STMT_PACKAGE &&
945 child->get_comment() ) {
946 statement::comment doc(child->get_comment());
947 string tid = doc.get_pkgdoc_tid();
948 if( tid.size() )
949 type = tid;
950 }
951 os << "<td align=left valign=top>"
952 << type
953 << " </td>";
954
955 // Scope/Access
956 os << "<td align=left valign=top>";
957 os << child->get_access_name();
958 os << "</td>";
959
960 // Source info
961 if( m_sw.rptsrc() ) {
962 os << "<td align=left valign=top>";
963 os << child->get_file() << ":" << child->get_lineno();
964 os << "</td>";
965 }
966
967 // Short description
968 os << "<td align=left valign=top>";
969 write_short_desc(os,child);
970 os << "</td>";
971
972 os << "</tr>\n";
973 }
974 os << "</table>\n";
975 }
976 write_unindent(os);
977 }
978 // ================================================================
979 // Indent.
980 // ================================================================
write_indent(ostream & os) const981 void ccdoc::phase3::html::write_indent(ostream& os) const
982 {
983 #if 0
984 // <blockquote> uses fewer characters
985 os << "<table><tr><td>&nsp;&nsp;&nsp;&nsp;</td><td>\n";
986 #endif
987 os << "<blockquote>\n";
988 }
989 // ================================================================
990 // Unindent.
991 // ================================================================
write_unindent(ostream & os) const992 void ccdoc::phase3::html::write_unindent(ostream& os) const
993 {
994 #if 0
995 os << "</td></table>\n";
996 #endif
997 os << "</blockquote>\n";
998 }
999 // ================================================================
1000 // Section header.
1001 // ================================================================
write_section_header(ostream & os,const char * title,bool contents,const char * prev,const char * next)1002 void ccdoc::phase3::html::write_section_header(ostream& os,
1003 const char* title,
1004 bool contents,
1005 const char* prev,
1006 const char* next)
1007 {
1008 os << "<hr>"
1009 << "<table width=\"100%\" border=0 cellpadding=0 cellspacing=0>"
1010 << "<tr>"
1011 << "<td align=left valign=top>"
1012 << "<h2>" << title << "</h2>"
1013 << "</td>"
1014 << "<td align=right valign=top>";
1015 if( contents ) {
1016 os << "<a href=\"#ccdoc_contents\">?</a> ";
1017 }
1018 os << "<a href=\"#ccdoc_top\">^</a> \n";
1019 if( prev && *prev ) {
1020 os << "<a href=\"#" << prev << "\"><</a> ";
1021 }
1022 if( next && *next ) {
1023 os << "<a href=\"#" << next << "\">></a> ";
1024 }
1025 os << "</td>"
1026 << "</tr>"
1027 << "</table>\n";
1028 }
1029 // ================================================================
1030 // Section header.
1031 // ================================================================
write_section_header(ostream & os,statement::base * stmt,bool contents,const char * prev,const char * next)1032 void ccdoc::phase3::html::write_section_header(ostream& os,
1033 statement::base* stmt,
1034 bool contents,
1035 const char* prev,
1036 const char* next)
1037 {
1038 if( stmt ) {
1039 string id = format_string_for_html(stmt->get_id()) ;
1040 string title;
1041 if( stmt->get_type() == statement::base::STMT_PACKAGE ) {
1042 // Issue 31 - The user might have specified their own package tag.
1043 title = stmt->get_type_name2();
1044 if( stmt->get_comment() ) {
1045 statement::comment doc(stmt->get_comment());
1046 string tid = doc.get_pkgdoc_tid();
1047 if( tid.size() ) {
1048 title = tid;
1049 }
1050 }
1051 }
1052 else if( stmt->get_template() ) {
1053 // This is a template, output the template information in the
1054 // title.
1055 title = "<font size=\"-1\">";
1056 // Capture the template information.
1057 const ccdoc::statement::base::cstrs_t tokens = stmt->get_tokens();
1058 ccdoc::statement::base::cstrs_citr_t itr1 = tokens.begin();
1059 int level = 0;
1060 for(;itr1!=tokens.end();++itr1) {
1061 string tmp = *itr1;
1062 title += tmp;
1063 title += " ";
1064 if( tmp == "<" ) {
1065 ++level;
1066 }
1067 else if( tmp == ">" ) {
1068 --level;
1069 if( level == 0 )
1070 break;
1071 }
1072 }
1073 title += "</font><br>";
1074 title += stmt->get_type_name2();
1075 }
1076 // The "operator" keyword is already built into the operator id.
1077 else if( stmt->get_type() != statement::base::STMT_FUNCTION_OPERATOR &&
1078 stmt->get_type() != statement::base::STMT_METHOD_OPERATOR ) {
1079 title = stmt->get_type_name2();
1080 }
1081 title += " ";
1082 title += id;
1083 write_section_header(os,title.c_str(),contents,prev,next);
1084 }
1085 else {
1086 write_section_header(os,"unknown",contents,prev,next);
1087 }
1088 }
1089 // ================================================================
1090 // Code begin
1091 // ================================================================
code_begin(ostream & os)1092 void ccdoc::phase3::html::code_begin(ostream& os)
1093 {
1094 os << "<blockquote>";
1095 os << "<pre>";
1096 os << endl;
1097 }
1098 // ================================================================
1099 // Code end
1100 // ================================================================
code_end(ostream & os)1101 void ccdoc::phase3::html::code_end(ostream& os) {
1102 os << "</pre>";
1103 os << "</blockquote>";
1104 os << endl;
1105 }
1106 // ================================================================
1107 // Load
1108 // ================================================================
load(const string & fn,string & contents)1109 void ccdoc::phase3::html::load(const string& fn,
1110 string& contents)
1111 {
1112 if( fn.size() ) {
1113 if( m_sw.verbose() ) {
1114 s_log << "loading " << fn.c_str() << " ...\n";
1115 }
1116 ifstream is(fn.c_str());
1117 if( !is ) {
1118 s_log.warning()
1119 << "Cannot read file '"
1120 << fn.c_str()
1121 << "'\n"
1122 << s_log.enable();
1123 return;
1124 }
1125 // Read the file (including whitespace) into the contents string.
1126 char ch;
1127 while( is.get(ch) ) {
1128 contents += ch;
1129 }
1130 }
1131 }
1132 // ================================================================
1133 // Write out the code section.
1134 // ================================================================
write_code_section(ostream & os,statement::base * stmt)1135 void ccdoc::phase3::html::write_code_section(ostream& os,
1136 statement::base* stmt)
1137 {
1138 // The first step is to group the tokens that are
1139 // associated by '::'.
1140 statement::base::strs_t grouped_tokens;
1141 {
1142 const statement::base::cstrs_t& src = stmt->get_tokens();
1143 statement::base::cstrs_citr_t itr = src.begin();
1144 for(;itr!=src.end();++itr) {
1145 string x = *itr;
1146 if( x == "::" ) {
1147 string token;
1148 if( grouped_tokens.size() ) {
1149 token = grouped_tokens.back();
1150 grouped_tokens.pop_back();
1151 }
1152 token += *itr;
1153 ++itr;
1154 if( itr != src.end() ) {
1155 token += *itr;
1156 }
1157 grouped_tokens.push_back(token);
1158 }
1159 else {
1160 grouped_tokens.push_back(x);
1161 }
1162 }
1163 }
1164
1165 // Output the code portion.
1166 os << "<dl><dt><b>Code:</b></dt><dd>";
1167 if( stmt->get_type() == statement::base::STMT_ATTRIBUTE ||
1168 stmt->get_type() == statement::base::STMT_ATTRIBUTE_FUNCTION ) {
1169 write_code_subsection_var(os,stmt,grouped_tokens);
1170 }
1171 else if( stmt->get_type() == statement::base::STMT_FUNCTION ||
1172 stmt->get_type() == statement::base::STMT_METHOD_CONSTRUCTOR ||
1173 stmt->get_type() == statement::base::STMT_METHOD_DESTRUCTOR ||
1174 stmt->get_type() == statement::base::STMT_METHOD ) {
1175 write_code_subsection_fct(os,stmt,grouped_tokens);
1176 }
1177 else if( stmt->get_type() == statement::base::STMT_FUNCTION_OPERATOR ||
1178 stmt->get_type() == statement::base::STMT_METHOD_OPERATOR ) {
1179 write_code_subsection_opr(os,stmt,grouped_tokens);
1180 }
1181 else if( stmt->get_type() == statement::base::STMT_ENUM ) {
1182 write_code_subsection_enum(os,stmt,grouped_tokens);
1183 }
1184 else if( stmt->get_type() == statement::base::STMT_VARIABLE ||
1185 stmt->get_type() == statement::base::STMT_VARIABLE_FUNCTION ) {
1186 write_code_subsection_var(os,stmt,grouped_tokens);
1187 }
1188 else {
1189 if( m_sw.rptfwcf() )
1190 os << "<code>"; // Issue 0045
1191 os << stmt->get_access_name() << " ";
1192 string external_linkage = stmt->get_extern();
1193 if( external_linkage.size() )
1194 os << "extern " << external_linkage << " ";
1195 statement::base::strs_itr_t itr = grouped_tokens.begin();
1196 for(;itr!=grouped_tokens.end();++itr) {
1197 string& token = *itr;
1198 if( itr != grouped_tokens.begin() ) {
1199 os << " ";
1200 }
1201 write_code_subsection_token(os,stmt,token);
1202 }
1203 if( m_sw.rptfwcf() )
1204 os << "</code>"; // Issue 0045
1205 os << "\n";
1206 }
1207 os << "</dd></dl>\n";
1208 }
1209 // ================================================================
1210 // Write out the code section for variables.
1211 // ================================================================
write_code_subsection_var(ostream & os,statement::base * stmt,statement::base::strs_t & group)1212 void ccdoc::phase3::html::write_code_subsection_var(ostream& os,
1213 statement::base* stmt,
1214 statement::base::strs_t& group)
1215 {
1216 // ================================================
1217 // There is some special case handling here for
1218 // variables with no type.
1219 // ================================================
1220 if( m_sw.rptfwcf() )
1221 os << "<code>"; // Issue 0045
1222 os << stmt->get_access_name() << " ";
1223 string external_linkage = stmt->get_extern();
1224 if( external_linkage.size() )
1225 os << "extern " << external_linkage << " ";
1226 statement::base::strs_t& vec1 = group;
1227 if( vec1.size() == 1 ) {
1228 // This is the special case of a variable that
1229 // was declared as part of a class, struct, union
1230 // or enum declaration of the form:
1231 // enum AA {A,B,C} var;
1232 statement::base* parent = stmt->get_parent();
1233 bool found = false;
1234 if( parent ) {
1235 statement::base::stmts_t& vec2 = parent->get_children();
1236 statement::base::stmts_itr_t itr2 = vec2.begin();
1237 for(;itr2!=vec2.end();++itr2) {
1238 if( *itr2 == stmt ) {
1239 break;
1240 }
1241 }
1242 // We found the statement, now back up until we find
1243 // an enum, class, struct or union. Variables of the
1244 // form int a,b,c; are handled in the parsing phase.
1245 if( stmt == *itr2 ) {
1246 for(;itr2!=vec2.begin();--itr2) {
1247 statement::base* end = *itr2;
1248 bool done = false;
1249 switch( end->get_type() ) {
1250 case statement::base::STMT_ENUM:
1251 done = true;
1252 write_link(os,end);
1253 found = true;
1254 break;
1255 case statement::base::STMT_CLASS_END:
1256 case statement::base::STMT_STRUCT_END:
1257 case statement::base::STMT_UNION_END:
1258 {
1259 done = true;
1260 statement::base* begin = end->get_matching_begin();
1261 if( begin ) {
1262 write_link(os,begin);
1263 found = true;
1264 }
1265 break;
1266 }
1267 default:
1268 break;
1269 }
1270 if(done)
1271 break;
1272 }
1273 }
1274 }
1275 if( !found ) {
1276 // TODO: create a test for this error condition.
1277 // It is not clear how this could be done. Perhaps this
1278 // is dead code.
1279 os << "<font color=red>unknown_type</font>";
1280 // Issue 109:
1281 s_log.warning()
1282 << "UNDEF: Unknown type for variable '"
1283 << stmt->get_id()
1284 << "' at line "
1285 << stmt->get_lineno()
1286 << " in file "
1287 << stmt->get_file()
1288 << "\n"
1289 << s_log.enable();
1290 }
1291 os << " ";
1292 }
1293
1294 statement::base::strs_itr_t itr1 = vec1.begin();
1295 for(;itr1!=vec1.end();++itr1) {
1296 string& token = *itr1;
1297 if( itr1 != vec1.begin() ) {
1298 os << " ";
1299 }
1300 write_code_subsection_token(os,stmt,token);
1301 }
1302 os << "\n";
1303 if( m_sw.rptfwcf() )
1304 os << "</code>"; // Issue 0045
1305 }
1306 // ================================================================
1307 // Write out the code section for functions.
1308 // ================================================================
write_code_subsection_fct(ostream & os,statement::base * stmt,statement::base::strs_t & group)1309 void ccdoc::phase3::html::write_code_subsection_fct(ostream& os,
1310 statement::base* stmt,
1311 statement::base::strs_t& group)
1312 {
1313 // Here is where we get a bit fancy. The arguments are aligned
1314 // somewhat.
1315 statement::base::strs_t& vec1 = group;
1316 statement::base::strs_itr_t itr1 = vec1.begin();
1317 bool found_id = false;
1318 bool found_arg_lp = false;
1319 int depth = 0;
1320 os << "<table><tr><td nowrap valign=top>";
1321 if( m_sw.rptfwcf() )
1322 os << "<code>"; // Issue 0045
1323 os << stmt->get_access_name() << " ";
1324 string external_linkage = stmt->get_extern();
1325 if( external_linkage.size() )
1326 os << "extern " << external_linkage << " ";
1327 for(;itr1!=vec1.end();++itr1) {
1328 string& token = *itr1;
1329 if( itr1 != vec1.begin() ) {
1330 os << " ";
1331 }
1332 if( !found_id && token == stmt->get_id() ) {
1333 found_id = true;
1334 os << "<b>";
1335 write_code_subsection_token(os,stmt,token);
1336 os << "</b>";
1337 }
1338 else {
1339 write_code_subsection_token(os,stmt,token);
1340 }
1341
1342 if( token == "(" )
1343 depth++;
1344 else if( token == ")" )
1345 depth--;
1346 if(!found_arg_lp && found_id && depth==1) {
1347 found_arg_lp = true;
1348 if( m_sw.rptfwcf() )
1349 os << "</code>"; // Issue 0045
1350 os << "</td><td nowrap valign=top>";
1351 if( m_sw.rptfwcf() )
1352 os << "<code>"; // Issue 0045
1353 }
1354 if( depth == 1 && token == "," ) {
1355 if( m_sw.rptfwcf() )
1356 os << "</code>"; // Issue 0045
1357 os << "</td></tr><tr><td nowrap valign=top> "
1358 << "</td><td nowrap valign=top>";
1359 if( m_sw.rptfwcf() )
1360 os << "<code>"; // Issue 0045
1361 }
1362 }
1363 if( m_sw.rptfwcf() )
1364 os << "</code>"; // Issue 0045
1365 os << "</td></tr></table>\n";
1366 }
1367 // ================================================================
1368 // Write out the code section for operator functions.
1369 // ================================================================
write_code_subsection_opr(ostream & os,statement::base * stmt,statement::base::strs_t & group)1370 void ccdoc::phase3::html::write_code_subsection_opr(ostream& os,
1371 statement::base* stmt,
1372 statement::base::strs_t& group)
1373 {
1374 // Here is where we get a bit fancy. The arguments are aligned
1375 // somewhat.
1376 statement::base::strs_t& vec1 = group;
1377 statement::base::strs_itr_t itr1 = vec1.begin();
1378 bool found_id = false;
1379 bool found_arg_lp = false;
1380 int depth = 0;
1381 os << "<table><tr><td nowrap valign=top>";
1382 if( m_sw.rptfwcf() )
1383 os << "<code>"; // Issue 0045
1384 os << stmt->get_access_name() << " ";
1385 string external_linkage = stmt->get_extern();
1386 if( external_linkage.size() )
1387 os << "extern " << external_linkage << " ";
1388 // Walk through the statement tokens.
1389 // If it is an operator, it will be recognized
1390 // by the presence of the "operator" keyword.
1391 for(;itr1!=vec1.end();++itr1) {
1392 string& token = *itr1;
1393 if( itr1 != vec1.begin() ) {
1394 os << " ";
1395 }
1396 if( !found_id && token == "operator" ) {
1397 found_id = true;
1398 os << "<b>";
1399 token = stmt->get_id();
1400 write_code_subsection_token(os,stmt,token);
1401 os << "</b>";
1402 // Now skip ahead to the lp.
1403 if( token == "operator ()" ) {
1404 // Special case.
1405 ++itr1;
1406 ++itr1;
1407 }
1408 else {
1409 for(;itr1!=vec1.end();++itr1) {
1410 if( *itr1 == "(" ) {
1411 --itr1;
1412 break;
1413 }
1414 }
1415 }
1416 }
1417 else {
1418 write_code_subsection_token(os,stmt,token);
1419 }
1420
1421 if( token == "(" ) {
1422 depth++;
1423 }
1424 else if( token == ")" ) {
1425 depth--;
1426 }
1427 if( !found_arg_lp && found_id && depth==1 ) {
1428 found_arg_lp = true;
1429 if( m_sw.rptfwcf() )
1430 os << "</code>"; // Issue 0045
1431 os << "</td><td nowrap valign=top>";
1432 if( m_sw.rptfwcf() )
1433 os << "<code>"; // Issue 0045
1434 }
1435 if( depth == 1 && token == "," ) {
1436 if( m_sw.rptfwcf() )
1437 os << "</code>"; // Issue 0045
1438 os << "</td></tr><tr><td nowrap valign=top> "
1439 << "</td><td nowrap valign=top>";
1440 if( m_sw.rptfwcf() )
1441 os << "<code>"; // Issue 0045
1442 }
1443 }
1444 if( m_sw.rptfwcf() )
1445 os << "</code>"; // Issue 0045
1446 os << "</td></tr></table>\n";
1447 }
1448 // ================================================================
1449 // Write out the code section for enums.
1450 // ================================================================
write_code_subsection_enum(ostream & os,statement::base * stmt,statement::base::strs_t & group)1451 void ccdoc::phase3::html::write_code_subsection_enum(ostream& os,
1452 statement::base* stmt,
1453 statement::base::strs_t& group)
1454 {
1455 // Here is where we get a bit fancy. The arguments are aligned
1456 // somewhat.
1457 statement::base::strs_t& vec1 = group;
1458 statement::base::strs_itr_t itr1 = vec1.begin();
1459 bool found_id = false;
1460 bool found_arg_lp = false;
1461 int depth = 0;
1462 os << "<table><tr><td nowrap valign=top>";
1463 if( m_sw.rptfwcf() )
1464 os << "<code>"; // Issue 0045
1465 os << stmt->get_access_name() << " ";
1466 string external_linkage = stmt->get_extern();
1467 if( external_linkage.size() )
1468 os << "extern " << external_linkage << " ";
1469 for(;itr1!=vec1.end();++itr1) {
1470 string& token = *itr1;
1471 if( itr1 != vec1.begin() ) {
1472 os << " ";
1473 }
1474 if( !found_id && token == stmt->get_id() ) {
1475 found_id = true;
1476 os << "<b>";
1477 write_code_subsection_token(os,stmt,token);
1478 os << "</b>";
1479 }
1480 else {
1481 write_code_subsection_token(os,stmt,token);
1482 }
1483
1484 if( token == "{" )
1485 depth++;
1486 else if( token == "}" )
1487 depth--;
1488 // The id is not checked for here because anonymuous
1489 // enums do not have ids.
1490 if(!found_arg_lp && depth==1) {
1491 found_arg_lp = true;
1492 if( m_sw.rptfwcf() )
1493 os << "</code>"; // Issue 0045
1494 os << "</td><td nowrap valign=top>";
1495 if( m_sw.rptfwcf() )
1496 os << "<code>"; // Issue 0045
1497 }
1498 if( depth == 1 && token == "," ) {
1499 if( m_sw.rptfwcf() )
1500 os << "</code>"; // Issue 0045
1501 os << "</td></tr><tr><td nowrap valign=top> "
1502 << "</td><td nowrap valign=top>";
1503 if( m_sw.rptfwcf() )
1504 os << "<code>"; // Issue 0045
1505 }
1506 }
1507 if( m_sw.rptfwcf() )
1508 os << "</code>"; // Issue 0045
1509 os << "</td></tr></table>\n";
1510 }
1511 // ================================================================
1512 // Write out token for code section.
1513 // ================================================================
write_code_subsection_token(ostream & os,statement::base * stmt,const string & token)1514 void ccdoc::phase3::html::write_code_subsection_token(ostream& os,
1515 statement::base* stmt,
1516 const string& token)
1517 {
1518 if( token.size() == 0 )
1519 return;
1520 if( token == "<" )
1521 os << "<";
1522 else if( token == ">" )
1523 os << ">";
1524 else if( token == "&" )
1525 os << "&";
1526 else if( token == "..." )
1527 os << "...";
1528 else if( token == stmt->get_id() ) {
1529 os << "<b>" << format_string_for_html(token) << "</b>";
1530 }
1531 else if( is_cxx_keyword(token) ) {
1532 os << "<font color=green><b>" << token << "</b></font>";
1533 }
1534 else if( ('a' <= token[0] && token[0] <= 'z' ) ||
1535 ('A' <= token[0] && token[0] <= 'Z' ) ||
1536 ('_' == token[0] ) ||
1537 ('$' == token[0] ) ) {
1538
1539 // ================================================
1540 // Do a simple search for local matches in the
1541 // parent.
1542 // This matches things like:
1543 // class A {
1544 // public:
1545 // A& operator = (const A&);
1546 // };
1547 // ================================================
1548 if( stmt->get_parent() ) {
1549 if( stmt->get_parent()->get_type() == statement::base::STMT_CLASS_BEGIN ||
1550 stmt->get_parent()->get_type() == statement::base::STMT_STRUCT_BEGIN ||
1551 stmt->get_parent()->get_type() == statement::base::STMT_UNION_BEGIN ) {
1552 if( token == stmt->get_parent()->get_id() ) {
1553 os << "<b>" << format_string_for_html(token) << "</b>";
1554 return;
1555 }
1556 }
1557 }
1558
1559 // ================================================
1560 // Issue 0118
1561 // tokenize the id
1562 // A::B::C becomes A,B,C
1563 // ================================================
1564 vector<string> tokens;
1565 size_t beg=0;
1566 size_t end=beg;
1567 for(;end<token.size();++end) {
1568 if( end>beg && token[end] == ':' && token[end-1] == ':') {
1569 tokens.push_back( token.substr(beg,end-1) );
1570 beg = end+1;
1571 }
1572 }
1573 if(beg<end)
1574 tokens.push_back( token.substr(beg,end) );
1575
1576 // ================================================
1577 // Issue 0118
1578 // Recursively find matching statements, including
1579 // partial matches.
1580 // ================================================
1581 vector<statement::base*> matches;
1582 if( stmt->get_parent() ) {
1583 statement::base* parent = stmt->get_parent();
1584 for( ;parent; parent = parent->get_parent() ) {
1585 if( ignore_contents_stmt(parent) )
1586 break;
1587 write_code_subsection_token(matches,parent,tokens,0);
1588 if( matches.size() ) {
1589 write_links(os,matches,token.c_str());
1590 return;
1591 }
1592 }
1593 }
1594
1595 // ================================================
1596 // Check for links here by looking up entities
1597 // in the database. Begin by looking in the same
1598 // namespace.
1599 // ================================================
1600 statement::base::stmts_t token_stmts;
1601 m_db.get_stmt_no_pkgs(token,token_stmts);
1602 if( token_stmts.size() ) {
1603 // Filter the token statements by type.
1604 statement::base::stmts_t valid_token_stmts;
1605 statement::base::stmts_itr_t itr = token_stmts.begin();
1606 for(;itr!=token_stmts.end();++itr) {
1607 switch( (*itr)->get_type() ) {
1608 case statement::base::STMT_CLASS_BEGIN:
1609 case statement::base::STMT_STRUCT_BEGIN:
1610 case statement::base::STMT_UNION_BEGIN:
1611 case statement::base::STMT_ENUM:
1612 case statement::base::STMT_TYPEDEF_FUNCTION:
1613 case statement::base::STMT_TYPEDEF_VARIABLE:
1614 case statement::base::STMT_VARIABLE: // Issue 0091:
1615 case statement::base::STMT_VARIABLE_FUNCTION:
1616 case statement::base::STMT_FUNCTION:
1617 case statement::base::STMT_FUNCTION_OPERATOR:
1618 valid_token_stmts.push_back(*itr);
1619 break;
1620 default:
1621 break;
1622 }
1623 }
1624 if( valid_token_stmts.size() == 1 ) {
1625 // If there is only one, use it.
1626 write_link(os,valid_token_stmts[0],token.c_str());
1627 return;
1628 }
1629 else if( valid_token_stmts.size() > 1 ) {
1630 // If there is more than one statement that matches,
1631 // try finding it in the same namespace as the stmt.
1632 statement::base* nsp = 0;
1633 statement::base* parent = stmt->get_parent();
1634 while(parent) {
1635 if(parent->get_type() == statement::base::STMT_NAMESPACE_BEGIN) {
1636 nsp = parent;
1637 break;
1638 }
1639 parent = parent->get_parent();
1640 }
1641 statement::base::stmts_t valid_token_stmts_in_nsp;
1642 itr = valid_token_stmts.begin();
1643 for(;itr!=valid_token_stmts.end();++itr) {
1644 statement::base* nsp1 = 0;
1645 parent = *itr;
1646 while(parent) {
1647 if(parent->get_type() == statement::base::STMT_NAMESPACE_BEGIN) {
1648 nsp1 = parent;
1649 break;
1650 }
1651 parent = parent->get_parent();
1652 }
1653 if( nsp == nsp1 ) {
1654 valid_token_stmts_in_nsp.push_back(*itr);
1655 // Exit after one for efficiency.
1656 break;
1657 }
1658 }
1659 if( valid_token_stmts_in_nsp.size() ) {
1660 write_link(os,valid_token_stmts_in_nsp[0],token.c_str());
1661 return;
1662 }
1663 else {
1664 write_link(os,valid_token_stmts[0],token.c_str());
1665 return;
1666 }
1667 }
1668 }
1669 // No matching statements were found.
1670 os << format_string_for_html(token);
1671 }
1672 else {
1673 os << format_string_for_html(token);
1674 }
1675 }
1676 // ================================================================
1677 // Write out token for code section if it matches an id in
1678 // the specified scope.
1679 // ================================================================
write_code_subsection_token(ostream & os,statement::base::stmts_t & vec,const string & token)1680 bool ccdoc::phase3::html::write_code_subsection_token(ostream& os,
1681 statement::base::stmts_t& vec,
1682 const string& token)
1683 {
1684 statement::base::stmts_itr_t itr = vec.begin();
1685 for(;itr!=vec.end();++itr) {
1686 statement::base* stmt = *itr;
1687 if( token == stmt->get_id() ) {
1688 switch( stmt->get_type() ) {
1689 case statement::base::STMT_CLASS_BEGIN:
1690 case statement::base::STMT_STRUCT_BEGIN:
1691 case statement::base::STMT_UNION_BEGIN:
1692 case statement::base::STMT_ENUM:
1693 case statement::base::STMT_TYPEDEF_FUNCTION:
1694 case statement::base::STMT_TYPEDEF_VARIABLE:
1695 case statement::base::STMT_VARIABLE: // Issue 0091:
1696 case statement::base::STMT_VARIABLE_FUNCTION:
1697 case statement::base::STMT_FUNCTION:
1698 case statement::base::STMT_FUNCTION_OPERATOR:
1699 // Attach to the first one of the correct type.
1700 write_link(os,stmt,token.c_str());
1701 return true;
1702 default:
1703 break;
1704 }
1705 }
1706 }
1707 return false;
1708 }
1709 // ================================================================
1710 // Issue 0118
1711 // Match a partial specification.
1712 // the specified scope.
1713 // ================================================================
write_code_subsection_token(statement::base::stmts_t & vec,statement::base * stmt,const vector<string> & tokens,size_t idx) const1714 void ccdoc::phase3::html::write_code_subsection_token(statement::base::stmts_t& vec,
1715 statement::base* stmt,
1716 const vector<string>& tokens,
1717 size_t idx) const
1718 {
1719 vector<statement::base*> local_matches;
1720 stmt->get_children_by_id(local_matches,tokens[idx]);
1721 if( local_matches.size() ) {
1722 ++idx;
1723 vector<statement::base*>::iterator itr = local_matches.begin();
1724 for(;itr!=local_matches.end();++itr) {
1725 if( ignore_contents_stmt(*itr) )
1726 continue;
1727 if( idx < tokens.size() ) {
1728 write_code_subsection_token(vec,*itr,tokens,idx);
1729 }
1730 else {
1731 vec.push_back(*itr);
1732 }
1733 }
1734 }
1735 }
1736 // ================================================================
1737 // Is this a keyword.
1738 // ================================================================
is_cxx_keyword(const string & token)1739 bool ccdoc::phase3::html::is_cxx_keyword(const string& token)
1740 {
1741 if( m_keywords.size() == 0 ) {
1742 // ================================================
1743 // Load the keywords:
1744 // Table 3 (2.11)
1745 // ================================================
1746 m_keywords.insert("asm");
1747 m_keywords.insert("auto");
1748 m_keywords.insert("bool");
1749 m_keywords.insert("break");
1750 m_keywords.insert("case");
1751 m_keywords.insert("catch");
1752 m_keywords.insert("char");
1753 m_keywords.insert("class");
1754 m_keywords.insert("const");
1755 m_keywords.insert("const_cast");
1756 m_keywords.insert("continue");
1757 m_keywords.insert("default");
1758 m_keywords.insert("delete");
1759 m_keywords.insert("do");
1760 m_keywords.insert("double");
1761 m_keywords.insert("dynamic_cast");
1762 m_keywords.insert("else");
1763 m_keywords.insert("enum");
1764 m_keywords.insert("explicit");
1765 m_keywords.insert("export");
1766 m_keywords.insert("extern");
1767 m_keywords.insert("false");
1768 m_keywords.insert("float");
1769 m_keywords.insert("for");
1770 m_keywords.insert("friend");
1771 m_keywords.insert("goto");
1772 m_keywords.insert("if");
1773 m_keywords.insert("inline");
1774 m_keywords.insert("int");
1775 m_keywords.insert("long");
1776 m_keywords.insert("mutable");
1777 m_keywords.insert("namespace");
1778 m_keywords.insert("new");
1779 m_keywords.insert("operator");
1780 m_keywords.insert("private");
1781 m_keywords.insert("protected");
1782 m_keywords.insert("public");
1783 m_keywords.insert("register");
1784 m_keywords.insert("reinterpret_cast");
1785 m_keywords.insert("return");
1786 m_keywords.insert("short");
1787 m_keywords.insert("signed");
1788 m_keywords.insert("sizeof");
1789 m_keywords.insert("static");
1790 m_keywords.insert("static_cast");
1791 m_keywords.insert("struct");
1792 m_keywords.insert("switch");
1793 m_keywords.insert("template");
1794 m_keywords.insert("this");
1795 m_keywords.insert("throw");
1796 m_keywords.insert("true");
1797 m_keywords.insert("try");
1798 m_keywords.insert("typedef");
1799 m_keywords.insert("typeid");
1800 m_keywords.insert("typename");
1801 m_keywords.insert("union");
1802 m_keywords.insert("unsigned");
1803 m_keywords.insert("using");
1804 m_keywords.insert("virtual");
1805 m_keywords.insert("void");
1806 m_keywords.insert("volatile");
1807 m_keywords.insert("wchar_t");
1808 m_keywords.insert("while");
1809
1810 // ================================================
1811 // Add in the alternate representations for some
1812 // of the operators and punctuators.
1813 // ================================================
1814 m_keywords.insert("and");
1815 m_keywords.insert("and_eq");
1816 m_keywords.insert("bitand");
1817 m_keywords.insert("bitor");
1818 m_keywords.insert("compl");
1819 m_keywords.insert("not");
1820 m_keywords.insert("not_eq");
1821 m_keywords.insert("or");
1822 m_keywords.insert("or_eq");
1823 m_keywords.insert("xor");
1824 m_keywords.insert("xor_eq");
1825 }
1826 set<string>::const_iterator itr = m_keywords.find(token);
1827 return itr != m_keywords.end();
1828 }
1829 // ================================================================
1830 // Compare statements for the make_contents() algorithm.
1831 // ================================================================
1832 namespace
1833 {
compare_stmts_full_paths(const ccdoc::statement::base * a,const ccdoc::statement::base * b)1834 bool compare_stmts_full_paths(const ccdoc::statement::base* a,
1835 const ccdoc::statement::base* b)
1836 {
1837 assert(a);
1838 assert(b);
1839 string a_id;
1840 string b_id;
1841 a->get_hier_id(a_id);
1842 b->get_hier_id(b_id);
1843
1844 // Do a case insensitive compare to make things easier
1845 // to find.
1846 const char* p1 = a_id.c_str();
1847 const char* p2 = b_id.c_str();
1848 for(;*p1 && *p2;++p1,++p2) {
1849 if( *p1 != *p2 ) {
1850 int ch1 = *p1;
1851 int ch2 = *p2;
1852 // Convert to upper case.
1853 if( 'a' <= ch1 && ch1 <= 'z' )
1854 ch1 = ( ch1 - 'a' ) + 'A';
1855 if( 'a' <= ch2 && ch2 <= 'z' )
1856 ch2 = ( ch2 - 'a' ) + 'A';
1857 if( ch1 != ch2 )
1858 return ch1 < ch2;
1859 }
1860 }
1861 return *p1 < *p2;
1862 }
1863 }
1864 // ================================================================
1865 // Compare statements for the make_contents() algorithm.
1866 // ================================================================
1867 namespace
1868 {
compare_stmts(const ccdoc::statement::base * a,const ccdoc::statement::base * b)1869 bool compare_stmts(const ccdoc::statement::base* a,
1870 const ccdoc::statement::base* b)
1871 {
1872 assert(a);
1873 assert(b);
1874 // Special cases:
1875 // Destructors always show up before first.
1876 if( a->get_type() == ccdoc::statement::base::STMT_METHOD_DESTRUCTOR ) {
1877 return true; // a<b
1878 }
1879 if( b->get_type() == ccdoc::statement::base::STMT_METHOD_DESTRUCTOR ) {
1880 return false; // b<a
1881 }
1882 if( a->get_type() == ccdoc::statement::base::STMT_METHOD_CONSTRUCTOR ) {
1883 // Constructors always match.
1884 if( b->get_type() == ccdoc::statement::base::STMT_METHOD_CONSTRUCTOR ) {
1885 return false;
1886 }
1887 // Constructors always show up first.
1888 return true; // a<b
1889 }
1890 if( b->get_type() == ccdoc::statement::base::STMT_METHOD_CONSTRUCTOR ) {
1891 // Constructors always show up first.
1892 return false; // b<a
1893 }
1894
1895 string a_id;
1896 string b_id;
1897 if( a->get_type() == ccdoc::statement::base::STMT_PACKAGE ||
1898 a->get_type() == ccdoc::statement::base::STMT_NAMESPACE_BEGIN ) {
1899 if( ( b->get_type() == ccdoc::statement::base::STMT_PACKAGE ||
1900 b->get_type() == ccdoc::statement::base::STMT_NAMESPACE_BEGIN ) ) {
1901 // a and b are both packages or namespaces,
1902 // compare them hierarchically
1903 a->get_hier_id(a_id);
1904 b->get_hier_id(b_id);
1905 }
1906 else {
1907 // a is a package or namespace and b isn't
1908 // a is less than b.
1909 // Always put packages and namespaces first.
1910 return true;
1911 }
1912 }
1913 else if( ( b->get_type() == ccdoc::statement::base::STMT_PACKAGE ||
1914 b->get_type() == ccdoc::statement::base::STMT_NAMESPACE_BEGIN ) ) {
1915 // b is a package or namespace and a isn't
1916 // b is less than a.
1917 return false;
1918 }
1919 else {
1920 a_id = a->get_id();
1921 b_id = b->get_id();
1922 }
1923
1924 // Do a case insensitive compare to make things easier
1925 // to find.
1926 const char* p1 = a_id.c_str();
1927 const char* p2 = b_id.c_str();
1928 for(;*p1 && *p2;++p1,++p2) {
1929 if( *p1 != *p2 ) {
1930 int ch1 = *p1;
1931 int ch2 = *p2;
1932 // Convert to upper case.
1933 if( 'a' <= ch1 && ch1 <= 'z' )
1934 ch1 = ( ch1 - 'a' ) + 'A';
1935 if( 'a' <= ch2 && ch2 <= 'z' )
1936 ch2 = ( ch2 - 'a' ) + 'A';
1937 if( ch1 != ch2 )
1938 return ch1 < ch2;
1939 }
1940 }
1941 return *p1 < *p2;
1942 }
1943 }
1944 // ================================================================
1945 // Make contents.
1946 // This is used to get list of entities for contents and sections.
1947 // ================================================================
make_contents(statement::base * stmt,statement::base::stmts_t & contents,bool sort_flag)1948 void ccdoc::phase3::html::make_contents(statement::base* stmt,
1949 statement::base::stmts_t& contents,
1950 bool sort_flag)
1951 {
1952 // ================================================
1953 // Filter out the children that we don't care
1954 // about on this run.
1955 // ================================================
1956 statement::base::stmts_t& children = stmt->get_children();
1957 if( children.size() ) {
1958 statement::base::stmts_itr_t itr = children.begin();
1959 for(;itr!=children.end();++itr) {
1960 statement::base* child = *itr;
1961 if(ignore_contents_stmt(child))
1962 continue;
1963
1964 // ================================================
1965 // Special case handling for namespaces and packages,
1966 // we provide nested information for them.
1967 // ================================================
1968 if( child->get_type() == statement::base::STMT_PACKAGE ) {
1969 statement::base::stmts_t vec1;
1970 make_pkg_index_children(child,vec1);
1971 statement::base::stmts_itr_t itr1 = vec1.begin();
1972 for(;itr1!=vec1.end();++itr1) {
1973 contents.push_back(*itr1);
1974 }
1975 // Additional special case handling for packages.
1976 // Look for child namespaces that are stored as tokens.
1977 const statement::base::cstrs_t& nsps = child->get_tokens();
1978 statement::base::cstrs_citr_t nsps_itr = nsps.begin();
1979 for(;nsps.begin()!=nsps.end();++nsps_itr) {
1980 string token = *nsps_itr;
1981 statement::base::stmts_t nsp_stmts;
1982 m_db.get_stmt_no_pkgs(token,nsp_stmts);
1983
1984 // Filter out the statements that don't have packages as
1985 // parents. Add the top namespaces to the contents list.
1986 statement::base::stmts_itr_t nsp_stmts_itr = nsp_stmts.begin();
1987 for(;nsp_stmts_itr!=nsp_stmts.end();++nsp_stmts_itr) {
1988 statement::base* nsp = *nsp_stmts_itr;
1989 if( nsp->get_parent()->get_type() == statement::base::STMT_PACKAGE ) {
1990 vec1.clear();
1991 make_pkg_index_children(nsp,vec1);
1992 for(itr1 = vec1.begin();itr1!=vec1.end();++itr1) {
1993 contents.push_back(*itr1);
1994 }
1995 }
1996 }
1997 }
1998 }
1999 else if( child->get_type() == statement::base::STMT_NAMESPACE_BEGIN ) {
2000 statement::base::stmts_t vec1;
2001 make_pkg_index_children(child,vec1);
2002 statement::base::stmts_itr_t itr1 = vec1.begin();
2003 for(;itr1!=vec1.end();++itr1) {
2004 contents.push_back(*itr1);
2005 }
2006 }
2007 else {
2008 contents.push_back(child);
2009 }
2010 }
2011 }
2012
2013 // ================================================
2014 // Load parent class contents.
2015 // ================================================
2016 if( stmt->get_type() == statement::base::STMT_CLASS_BEGIN ||
2017 stmt->get_type() == statement::base::STMT_STRUCT_BEGIN ) {
2018 make_class_contents(stmt,contents);
2019 }
2020
2021 // ================================================
2022 // Sort the remaining children by name.
2023 // ================================================
2024 if( sort_flag ) {
2025 // Use a stable sort here so that we don't have
2026 // to worry about how equivalent entries are
2027 // handled. Duplicate entries are expected. The
2028 // most common cause is overloaded methods.
2029 // This is verified by test88.
2030 //sort(contents.begin(),contents.end(),compare_stmts); // fails
2031 stable_sort(contents.begin(),contents.end(),compare_stmts); // Issue 0183
2032 }
2033 }
2034 // ================================================================
2035 // Make class contents.
2036 // This is used to get list of entities for contents and sections.
2037 // Classes are a special case because we also get the inherited
2038 // methods.
2039 // ================================================================
make_class_contents(statement::base * stmt,statement::base::stmts_t & contents)2040 void ccdoc::phase3::html::make_class_contents(statement::base* stmt,
2041 statement::base::stmts_t& contents)
2042 {
2043 if( m_sw.rptim() ) {
2044 // ================================================
2045 // Get the classes that this class derives from.
2046 // ================================================
2047 statement::base::stmts_t classes;
2048 load_inheritance_classes(stmt,classes);
2049 if( classes.size() == 0 )
2050 return;
2051
2052 // ================================================
2053 // Populate the used_method_ids with the contents
2054 // of the original class.
2055 // ================================================
2056 statement::base::stmts_t used_classes;
2057 set<string> used_method_ids;
2058 statement::base::stmts_itr_t contents_itr = contents.begin();
2059 for(;contents_itr!=contents.end();++contents_itr) {
2060 statement::base* rec = *contents_itr;
2061 if( rec->get_type() == statement::base::STMT_METHOD ) {
2062 string key = rec->get_id();
2063 used_method_ids.insert( key );
2064 }
2065 }
2066 if( classes.size() )
2067 make_class_contents(contents,classes,used_classes,used_method_ids);
2068 }
2069 }
2070 // ================================================================
2071 // Make class contents.
2072 // This is used to get list of entities for contents and sections.
2073 // Classes are a special case because we also get the inherited
2074 // methods.
2075 // ================================================================
make_class_contents(statement::base::stmts_t & contents,statement::base::stmts_t & classes,statement::base::stmts_t & used_classes,set<string> & used_method_ids)2076 void ccdoc::phase3::html::make_class_contents(statement::base::stmts_t& contents,
2077 statement::base::stmts_t& classes,
2078 statement::base::stmts_t& used_classes,
2079 set<string>& used_method_ids)
2080 {
2081 // ================================================
2082 // Iterate over each of the parent classes to
2083 // capture their methods. Ignore methods that
2084 // have already been defined.
2085 // ================================================
2086 statement::base::stmts_itr_t classes_itr = classes.begin();
2087 for(;classes_itr!=classes.end();++classes_itr) {
2088 statement::base* class_rec = *classes_itr;
2089
2090 // This is an O(N^2) test to verify that we don't have
2091 // an inheritance loop. The performance s/b ok because
2092 // the inheritance depth s/b small (<10).
2093 statement::base::stmts_itr_t used_classes_itr = used_classes.begin();
2094 for(;used_classes_itr!=used_classes.end();++used_classes_itr) {
2095 if( *used_classes_itr == class_rec ) {
2096 break;
2097 }
2098 }
2099 if( used_classes_itr != used_classes.end() )
2100 continue;
2101 used_classes.push_back(class_rec);
2102
2103 // Add methods to the contents.
2104 statement::base::stmts_t& children = class_rec->get_children();
2105 statement::base::stmts_itr_t children_itr = children.begin();
2106 for(;children_itr!=children.end();++children_itr) {
2107 statement::base* rec = *children_itr;
2108 if( rec->get_type() == statement::base::STMT_METHOD ) {
2109 if( !ignore_contents_stmt(rec) ) { // Issue 0040
2110 string key = rec->get_id();
2111 if( used_method_ids.find( key ) == used_method_ids.end() ) {
2112 contents.push_back( rec );
2113 }
2114 }
2115 }
2116 }
2117
2118 // Walk back through and update the use_method_ids.
2119 // This is not done as the methods are traversed
2120 // because we want to capture functions with the
2121 // same ids but different signatures.
2122 children_itr = children.begin();
2123 for(;children_itr!=children.end();++children_itr) {
2124 statement::base* rec = *children_itr;
2125 if( rec->get_type() == statement::base::STMT_METHOD ) {
2126 if( !ignore_contents_stmt(rec) ) { // Issue 0040
2127 string key = rec->get_id();
2128 if( used_method_ids.find( key ) == used_method_ids.end() ) {
2129 used_method_ids.insert( key );
2130 }
2131 }
2132 }
2133 }
2134
2135 // Load the parents of this class recursively.
2136 statement::base::stmts_t parent_classes;
2137 load_inheritance_classes(class_rec,parent_classes);
2138 if( parent_classes.size() )
2139 make_class_contents(contents,parent_classes,used_classes,used_method_ids);
2140 }
2141 }
2142 // ================================================================
2143 // Load the inheritance classes.
2144 // Load the classes that this class derives from.
2145 // ================================================================
load_inheritance_classes(statement::base * stmt,statement::base::stmts_t & classes)2146 void ccdoc::phase3::html::load_inheritance_classes(statement::base* stmt,
2147 statement::base::stmts_t& classes)
2148 {
2149 const statement::base::cstrs_t& tokens = stmt->get_tokens();
2150 statement::base::cstrs_citr_t tokens_itr = tokens.begin();
2151 for(;tokens_itr!=tokens.end();++tokens_itr) {
2152 string token = *tokens_itr;
2153 if( token == ":" ) {
2154 // This is where the interesting stuff starts.
2155 tokens_itr++;
2156 break;
2157 }
2158 }
2159 if( tokens_itr == tokens.end() ) {
2160 // No tokens.
2161 // This class does not derive from any other classes.
2162 return;
2163 }
2164
2165 bool found_id = false;
2166 int depth = 0;
2167 string id;
2168 for(;tokens_itr!=tokens.end();++tokens_itr) {
2169 string token = *tokens_itr;
2170 if( !found_id ) {
2171 if( token == "virtual" ||
2172 token == "public" ||
2173 token == "protected" ||
2174 token == "private" ) {
2175 continue;
2176 }
2177 found_id = true;
2178 }
2179 if( found_id ) {
2180 if( token == "<" ) {
2181 // This handles cases like:
2182 // class A : public foo<My1,My2> ;
2183 // class A : public foo<My1,My2<XX> > ;
2184 depth++;
2185 }
2186 else if( token == ">" ) {
2187 depth--;
2188 }
2189 else if( depth == 0 ) {
2190 if( token == "," ) {
2191 // Output the extends information.
2192 statement::base::stmts_t matches;
2193 if( 1 == load_extend_classes( id, matches, stmt ) ) {
2194 classes.push_back( matches[0] );
2195 }
2196 else {
2197 // TODO: Warn there there were multiple classes.
2198 }
2199 id = "";
2200 found_id = false;
2201 depth = 0;
2202 continue;
2203 }
2204 }
2205 id += token;
2206 }
2207 }
2208 statement::base::stmts_t matches;
2209 if( 1 == load_extend_classes( id, matches, stmt ) ) {
2210 classes.push_back( matches[0] );
2211 }
2212 else {
2213 // TODO: Warn there there were multiple classes.
2214 }
2215 }
2216 // ================================================================
2217 // Get the class record.
2218 // ================================================================
load_extend_classes(const string & id,statement::base::stmts_t & out,statement::base * stmt)2219 unsigned ccdoc::phase3::html::load_extend_classes(const string& id,
2220 statement::base::stmts_t& out,
2221 statement::base* stmt)
2222 {
2223 statement::base::stmts_t id_stmts;
2224 m_db.get_stmt_no_pkgs(id,id_stmts);
2225 if( id_stmts.size() == 0 ) {
2226 // Issue 0048
2227 string scoped_id;
2228 statement::base::stmts_t parents;
2229 stmt->get_parents_no_pkgs(parents);
2230 get_fully_scoped_name(scoped_id,id,parents);
2231 m_db.get_stmt_no_pkgs(scoped_id,id_stmts);
2232 if( id_stmts.size() == 0 )
2233 return 0;
2234 }
2235 if( id_stmts.size() > 0 ) {
2236 // Filter out the statements that are not classes or structs.
2237 statement::base::stmts_itr_t sitr = id_stmts.begin();
2238 for(;sitr!=id_stmts.end();++sitr) {
2239 statement::base* id_stmt = *sitr;
2240 if( id_stmt->get_type() == statement::base::STMT_CLASS_BEGIN ||
2241 id_stmt->get_type() == statement::base::STMT_STRUCT_BEGIN ) {
2242 out.push_back(id_stmt);
2243 }
2244 }
2245 }
2246 return out.size();
2247 }
2248 // ================================================================
2249 // Get the fully scoped name.
2250 // ================================================================
get_fully_scoped_name(string & out_id,const string & in_id,statement::base::stmts_t parents) const2251 void ccdoc::phase3::html::get_fully_scoped_name(string& out_id,
2252 const string& in_id,
2253 statement::base::stmts_t parents) const
2254 {
2255 statement::base::strs_t ids;
2256 m_db.parse_path(in_id,ids);
2257 if( parents.size() ) {
2258 bool doit = true;
2259 size_t last1 = 0;
2260 if( ids.size() > 1 ) {
2261 size_t sz1 = ids.size() - 1;
2262 size_t last2 = parents.size() - 1;
2263 last1 = sz1 - 1;
2264 for(;last1!=0 && last2!=0;--last1,--last2) {
2265 string nm = parents[last2]->get_id();
2266 if( nm != ids[last1] ) {
2267 doit = false;
2268 break;
2269 }
2270 }
2271 if( doit ) {
2272 // The match was found.
2273 last1 = sz1 - 1;
2274 }
2275 }
2276 if( doit ) {
2277 out_id = "";
2278 bool first = true;
2279 statement::base::stmts_itr_t itr = parents.begin();
2280 for(;itr!=parents.end();++itr) {
2281 if( !first )
2282 out_id += "::";
2283 out_id += (*itr)->get_id();
2284 first = false;
2285 }
2286 if( !first )
2287 out_id += "::";
2288 out_id += ids[last1];
2289 return;
2290 }
2291 }
2292 // Issue 0127
2293 // Check for the special case of B<int>.
2294 // This is invalid for a scoped name because
2295 // it cannot be looked up.
2296 out_id = in_id;
2297 string::size_type f = out_id.find('<');
2298 if( f != string::npos ) {
2299 out_id.erase(f);
2300 }
2301 }
2302 // ================================================================
2303 // Ignore a statement?
2304 // ================================================================
ignore_contents_stmt(statement::base * stmt) const2305 bool ccdoc::phase3::html::ignore_contents_stmt(statement::base* stmt) const
2306 {
2307 switch( stmt->get_type() ) {
2308 case statement::base::STMT_FRIEND_CLASS:
2309 case statement::base::STMT_FRIEND_FUNCTION:
2310 case statement::base::STMT_CLASS_END:
2311 case statement::base::STMT_COMMENT_PKGDOC:
2312 case statement::base::STMT_COMMENT_PKGDOC_URL:
2313 case statement::base::STMT_COMMENT_PREFIX:
2314 case statement::base::STMT_COMMENT_SUFFIX:
2315 case statement::base::STMT_IGNORE:
2316 case statement::base::STMT_NAMESPACE_END:
2317 case statement::base::STMT_STRUCT_END:
2318 case statement::base::STMT_UNION_END:
2319 case statement::base::STMT_MACROINST_FUNCTION:
2320 case statement::base::STMT_MACROINST_VARIABLE:
2321 // Ignore some of the statements all of the time.
2322 return true;
2323 case statement::base::STMT_MACRODEF_0_0:
2324 case statement::base::STMT_MACRODEF_0_1:
2325 case statement::base::STMT_MACRODEF_0_N:
2326 case statement::base::STMT_MACRODEF_N_N:
2327 if( !m_sw.rptmac() )
2328 return true;
2329 return false;
2330 case statement::base::STMT_TYPEDEF_FUNCTION:
2331 case statement::base::STMT_TYPEDEF_VARIABLE:
2332 if( !m_sw.rpttyp() )
2333 return true;
2334 // Don't return false until we check the
2335 // accessibility.
2336 break;
2337 case statement::base::STMT_UNION_BEGIN:
2338 if( !m_sw.rptun() )
2339 return true;
2340 // Don't return false until we check the
2341 // accessibility.
2342 break;
2343 #if 0
2344 // Issue 0073
2345 // This section of code was commented out because
2346 // ccdoc was reporting private methods when -norptpri was
2347 // specified.
2348 case statement::base::STMT_METHOD_CONSTRUCTOR:
2349 case statement::base::STMT_METHOD_DESTRUCTOR:
2350 // Ccdoc never ignores constructors, destructors and
2351 // assignment operators.
2352 return false;
2353 case statement::base::STMT_FUNCTION_OPERATOR:
2354 case statement::base::STMT_METHOD_OPERATOR:
2355 // Ccdoc never ignores assignment operators.
2356 if( stmt->get_id() ) {
2357 string id = stmt->get_id();
2358 if( id == "operator =" )
2359 return false;
2360 }
2361 break;
2362 #endif
2363 case statement::base::STMT_PACKAGE:
2364 if( stmt->get_parent() == m_db.root() ) {
2365 string id = stmt->get_id();
2366 if( id == "@null" || id == "[NULL]" ) {
2367 // Ignore top level packages that have the names
2368 // @null and [NULL].
2369 return true;
2370 }
2371 }
2372 break;
2373 case statement::base::STMT_NAMESPACE_BEGIN:
2374 // Skip the internal ids of the form:
2375 // +<name>+<file>:<line>
2376 if( stmt->get_id() && stmt->get_id()[0] == '+' )
2377 return true;
2378 break;
2379 default:
2380 break;
2381 }
2382
2383 // Check the accessibility.
2384 switch( stmt->get_access() ) {
2385 case statement::base::STMT_PRIVATE:
2386 return !m_sw.rptpri();
2387 case statement::base::STMT_PROTECTED:
2388 return !m_sw.rptpro();
2389 case statement::base::STMT_PUBLIC:
2390 return !m_sw.rptpub();
2391 default:
2392 break;
2393 }
2394
2395 return false;
2396 }
2397 // ================================================================
2398 // Write the package index html.
2399 // ================================================================
make_pkg_index_children(statement::base * stmt,statement::base::stmts_t & outvec)2400 void ccdoc::phase3::html::make_pkg_index_children(statement::base* stmt,
2401 statement::base::stmts_t& outvec)
2402 {
2403 if( stmt ) {
2404 if( stmt->get_type() != statement::base::STMT_NAMESPACE_BEGIN &&
2405 stmt->get_type() != statement::base::STMT_PACKAGE ) {
2406 return;
2407 }
2408 outvec.push_back(stmt);
2409 statement::base::stmts_t& vec = stmt->get_children();
2410 statement::base::stmts_itr_t itr = vec.begin();
2411 for(;itr!=vec.end();++itr) {
2412 make_pkg_index_children(*itr,outvec);
2413 }
2414 }
2415 }
2416 // ================================================================
2417 // Get the tag value for a statement.
2418 // ================================================================
make_tag_id(const statement::base * stmt,string & id) const2419 void ccdoc::phase3::html::make_tag_id(const statement::base* stmt,
2420 string& id) const
2421 {
2422 if(stmt) {
2423 id = stmt->get_terse_type_name();
2424 id += "-";
2425 id += format_name(stmt->get_id());
2426 if( stmt->get_type() == statement::base::STMT_FUNCTION ||
2427 stmt->get_type() == statement::base::STMT_FUNCTION_OPERATOR ||
2428 stmt->get_type() == statement::base::STMT_METHOD_CONSTRUCTOR ||
2429 stmt->get_type() == statement::base::STMT_METHOD_DESTRUCTOR ||
2430 stmt->get_type() == statement::base::STMT_METHOD_OPERATOR ||
2431 stmt->get_type() == statement::base::STMT_METHOD ) {
2432 // Append uniquifying tokens:
2433 const statement::base::cstrs_t& vec = stmt->get_tokens();
2434 statement::base::cstrs_citr_t itr = vec.begin();
2435 for(;itr!=vec.end();++itr) {
2436 id += "-";
2437 id += format_name( *itr );
2438 }
2439 }
2440 }
2441 }
2442 // ================================================================
2443 // Get the parent statement that defines a file entity.
2444 // ================================================================
2445 const ccdoc::statement::base*
get_file_stmt(const statement::base * stmt) const2446 ccdoc::phase3::html::get_file_stmt(const statement::base* stmt) const
2447 {
2448 // Other statements, such as functions are only in separate
2449 // files if they are at the top level. Otherwise they are
2450 // subordinated to a tag within a file.
2451 for(;stmt;stmt=stmt->get_parent()) {
2452 if( stmt->get_parent() == 0 )
2453 return stmt;
2454 // The only statement that does not have its own file is a
2455 // statement that is embedded in a class unless it is a subclass.
2456 if( stmt->get_type() == statement::base::STMT_CLASS_BEGIN ||
2457 stmt->get_type() == statement::base::STMT_STRUCT_BEGIN ||
2458 stmt->get_type() == statement::base::STMT_UNION_BEGIN ) {
2459 // Classes (even subclasses) always have their own files.
2460 return stmt;
2461 }
2462 if( stmt->get_parent()->get_type() != statement::base::STMT_CLASS_BEGIN &&
2463 stmt->get_parent()->get_type() != statement::base::STMT_STRUCT_BEGIN &&
2464 stmt->get_parent()->get_type() != statement::base::STMT_UNION_BEGIN ) {
2465 // Other statements that are not embedded in classes
2466 // always have their own files.
2467 return stmt;
2468 }
2469 }
2470 return stmt;
2471 }
2472 // ================================================================
2473 // Make file URL, strip off the leading directories.
2474 // ================================================================
make_file_url(string & url,string & fn) const2475 void ccdoc::phase3::html::make_file_url(string& url,string& fn) const
2476 {
2477 // Strip off the leading directories to
2478 // make the relative reference work.
2479 string::iterator itr = fn.begin();
2480 string::iterator relpath_itr = fn.begin();
2481 for(;itr!=fn.end();++itr) {
2482 if( '/' == *itr ) {
2483 relpath_itr = itr;
2484 ++relpath_itr; // Issue 0001 FIX
2485 }
2486 }
2487 url = "";
2488 for(;relpath_itr!=fn.end();++relpath_itr) {
2489 url += *relpath_itr;
2490 }
2491 }
2492 // ================================================================
2493 // Make file URL
2494 // ================================================================
make_file_url(string & url,const statement::base * stmt)2495 bool ccdoc::phase3::html::make_file_url(string& url,
2496 const statement::base* stmt)
2497 {
2498 if( stmt ) {
2499 const statement::base* file_stmt = get_file_stmt(stmt);
2500 string fn;
2501 make_unique_file_name(fn,file_stmt);
2502 make_file_url(url,fn);
2503
2504 // If the parent is the file statement, a tag needs to be
2505 // generated, return true.
2506 return file_stmt == stmt->get_parent();
2507 }
2508 return false;
2509 }
2510 // ================================================================
2511 // Make a unique file name that consistent between runs.
2512 // ================================================================
make_unique_file_name(string & fn,const statement::base * stmt)2513 void ccdoc::phase3::html::make_unique_file_name(string& fn,
2514 const statement::base* stmt)
2515 {
2516 if(stmt) {
2517 if( stmt->get_parent() == 0 ) {
2518 // This is the top node.
2519 // Perform special processing here to support the -rootfile
2520 // switch.
2521 if( m_sw.rootfile().size() ) {
2522 fn = m_sw.rootfile();
2523 return;
2524 }
2525 }
2526 bool append_tokens = false;
2527 if( stmt->get_type() == statement::base::STMT_FUNCTION ||
2528 stmt->get_type() == statement::base::STMT_FUNCTION_OPERATOR ||
2529 stmt->get_type() == statement::base::STMT_METHOD_CONSTRUCTOR ||
2530 stmt->get_type() == statement::base::STMT_METHOD_DESTRUCTOR ||
2531 stmt->get_type() == statement::base::STMT_METHOD_OPERATOR ||
2532 stmt->get_type() == statement::base::STMT_METHOD ) {
2533 append_tokens = true;
2534 }
2535 fn = m_sw.html() + "ccdoc";
2536
2537 // ================================================
2538 // Get the hierarchical names.
2539 // ================================================
2540 statement::base::stmts_t parents;
2541 stmt->get_parents(parents);
2542 if(parents.size()) {
2543 statement::base::stmts_itr_t itr = parents.begin();
2544
2545 // Handle the first argument as a special case.
2546 // We don't want the '@' sign in the file name.
2547 fn += ".";
2548 if( m_sw.default_root() == (*itr)->get_id() ) {
2549 fn += "root"; // strip of the leading @ for the file name.
2550 }
2551 else {
2552 fn += format_name( (*itr)->get_id() );
2553 }
2554 ++itr;
2555 for(;itr!=parents.end();++itr) {
2556 fn += ".";
2557 fn += format_name( (*itr)->get_id() );
2558 }
2559 // Tack on the statement id.
2560 fn += ".";
2561 fn += format_name( stmt->get_id() );
2562 }
2563 else {
2564 // This is the root package statement.
2565 // Handle the first argument as a special case.
2566 // We don't want the '@' sign in the file name.
2567 fn += ".";
2568 if( m_sw.default_root() == stmt->get_id() ) {
2569 fn += "root"; // strip of the leading @ for the file name.
2570 }
2571 else {
2572 fn += format_name( stmt->get_id() );
2573 }
2574 }
2575 string fn1 = fn;
2576
2577 // ================================================
2578 // Append the tokens for uniqueness for some types.
2579 // ================================================
2580 if( append_tokens ) {
2581 const statement::base::cstrs_t& vec = stmt->get_tokens();
2582 statement::base::cstrs_citr_t itr = vec.begin();
2583 for(;itr!=vec.end();++itr) {
2584 fn += ".";
2585 fn += format_name( *itr );
2586 }
2587 }
2588
2589 // ================================================
2590 // Append the type and html suffix.
2591 // ================================================
2592 fn += ".";
2593 fn += stmt->get_terse_type_name();
2594 fn += ".html";
2595 if( m_sw.maxpathlen() && fn.size() > m_sw.maxpathlen() ) {
2596 // Generate a checksum if the file name is too big.
2597 checksum c;
2598 c.set(fn.c_str());
2599
2600 char nbuf[32];
2601 sprintf(nbuf,"%08x",c.get());
2602
2603 fn = fn1;
2604 fn += ".checksum.";
2605 fn += nbuf;
2606 fn += ".";
2607 fn += stmt->get_terse_type_name();
2608 fn += ".html";
2609 }
2610 }
2611 }
2612 // ================================================================
2613 // Format the characters in an id so they are suitable for a file
2614 // name.
2615 // ================================================================
format_name(const char * token) const2616 const char* ccdoc::phase3::html::format_name(const char* token) const
2617 {
2618 static char out[65536];
2619 char nbuf[16];
2620 const char* src = token;
2621 char* dst = out;
2622 for(;*src;++src) {
2623 if( *src <= 32 || *src >= 127 ) {
2624 unsigned val = static_cast<unsigned>(*src);
2625 sprintf(nbuf,"-%02x",val);
2626 for(const char* p=nbuf;*p;++p)
2627 *dst++ = *p;
2628 }
2629 else {
2630 if( '{' == *src ) {
2631 // This only occurs for enum types and is
2632 // not necessary for uniquifying the name.
2633 *dst = 0;
2634 return out;
2635 }
2636 switch( *src ) {
2637 case '(':
2638 case ')':
2639 case '[':
2640 case ']':
2641 case '<':
2642 case '>':
2643 case ';':
2644 case ':':
2645 case '~':
2646 case '?':
2647 case '=':
2648 case ',':
2649 case '@':
2650 case '&':
2651 case '*':
2652 case '"':
2653 case '\'':
2654 case '/': // Issue 0018: filter embedded directory separators
2655 case '|': // Issue 0112: handle operator |
2656 case '\\':
2657 {
2658 unsigned val = static_cast<unsigned>(*src);
2659 sprintf(nbuf,"-%02x",val);
2660 for(const char* p=nbuf;*p;++p)
2661 *dst++ = *p;
2662 break;
2663 }
2664 default:
2665 *dst++ = *src;
2666 break;
2667 }
2668 }
2669 }
2670 *dst = 0;
2671 return out;
2672 }
2673 // ================================================================
2674 // format string (format for html)
2675 // ================================================================
format_string_for_html(const char * pstr) const2676 const char* ccdoc::phase3::html::format_string_for_html(const char* pstr) const
2677 {
2678 static char id[65536];
2679 char* p = id;
2680 if(pstr) {
2681 for(;*pstr;++pstr) {
2682 if( *pstr == '<' ) {
2683 *p++ = '&';
2684 *p++ = 'l';
2685 *p++ = 't';
2686 *p++ = ';';
2687 }
2688 else if( *pstr == '>' ) {
2689 *p++ = '&';
2690 *p++ = 'g';
2691 *p++ = 't';
2692 *p++ = ';';
2693 }
2694 else if( *pstr == '&' ) {
2695 *p++ = '&';
2696 *p++ = 'a';
2697 *p++ = 'm';
2698 *p++ = 'p';
2699 *p++ = ';';
2700 }
2701 else {
2702 *p++ = *pstr;
2703 }
2704 }
2705 }
2706 *p = 0;
2707 return id;
2708 }
2709 // ================================================================
2710 // format string (format for html)
2711 // ================================================================
2712 const char*
format_string_for_html(const string & str) const2713 ccdoc::phase3::html::format_string_for_html(const string& str) const
2714 {
2715 return format_string_for_html(str.c_str());
2716 }
2717 // ================================================================
2718 // write string (format for html)
2719 // ================================================================
write_html_formatted_string(ostream & os,const char * str) const2720 void ccdoc::phase3::html::write_html_formatted_string(ostream& os,
2721 const char* str) const
2722 {
2723 os << format_string_for_html(str);
2724 }
2725 // ================================================================
2726 // write string (format for html)
2727 // ================================================================
write_html_formatted_string(ostream & os,const string & str) const2728 void ccdoc::phase3::html::write_html_formatted_string(ostream& os,
2729 const string& str) const
2730 {
2731 write_html_formatted_string(os,str.c_str());
2732 }
2733 // ================================================================
2734 // write common header info
2735 // ================================================================
write_common_header_info(ostream & os,const string & fn,const char * title)2736 void ccdoc::phase3::html::write_common_header_info(ostream& os,
2737 const string& fn,
2738 const char* title)
2739 {
2740 os << "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
2741 << "<!--NewPage-->\n"
2742 << "<html>\n"
2743 << "<head>\n"
2744 ;
2745 if(m_meta.size()) {
2746 // Issue 0003: Write out the custom meta variables.
2747 os << m_meta << endl;
2748 }
2749 else {
2750 // Issue 0059:
2751 // Write out the content type to satisfy the HTML verifier
2752 // at http://validator.w3.org/.
2753 // Issue 0076:
2754 // Don't write out standard HTML meta elements if the -meta
2755 // switch was specified.
2756 os << "<meta http-equiv=\"Content-Type\" ";
2757 os << "content=\"text/html; ";
2758 os << "charset=" << m_sw.rptctcs() << "\">\n";
2759 }
2760 write_meta(os,"ccdoc_copyright" ,"(C) Joe Linoff 1998-2001");
2761 write_meta(os,"ccdoc_author" ,"Joe Linoff");
2762 write_meta(os,"ccdoc_version" ,m_sw.version().c_str());
2763 write_meta(os,"ccdoc_file" ,fn.c_str());
2764 write_meta(os,"ccdoc_creation_date" ,date_time());
2765 write_meta(os,"keywords" ,"ccdoc, source code, documentation");
2766 os << "<title>" << title << "</title>\n";
2767 os << "</head>\n" << "\n";
2768
2769 // ================================================
2770 // Write out the <body> prefix, including the
2771 // optional prefix that was supplied by the
2772 // user.
2773 // ================================================
2774 os << "<body";
2775 if(m_sw.bgcolor().size()) {
2776 os << " bgcolor=" << m_sw.bgcolor().c_str();
2777 }
2778 if(m_sw.fgtextcolor().size()) {
2779 os << " text=" << m_sw.fgtextcolor().c_str();
2780 }
2781 if(m_sw.fglinkcolor().size()) {
2782 os << " link=" << m_sw.fglinkcolor().c_str();
2783 }
2784 if(m_sw.fgvlinkcolor().size()) {
2785 os << " vlink=" << m_sw.fgvlinkcolor().c_str();
2786 }
2787 os << ">\n";
2788 os << "<a name=ccdoc_top></a>\n"; // Issue 0002
2789 if(m_header.size()) {
2790 os << m_header << endl;
2791 }
2792 }
2793 // ================================================================
2794 // write common header info
2795 // ================================================================
write_common_header_info(ostream & os,const string & fn,statement::base * stmt)2796 void ccdoc::phase3::html::write_common_header_info(ostream& os,
2797 const string& fn,
2798 statement::base* stmt)
2799 {
2800 string title = "ccdoc ";
2801 if( stmt ) {
2802 char nbuf[32];
2803 sprintf(nbuf,"%d",stmt->get_lineno());
2804 title += format_string_for_html(stmt->get_id());
2805 title += " ";
2806 title += stmt->get_file();
2807 title += ":";
2808 title += nbuf; // Issue 0010
2809 title += ":";
2810 title += stmt->get_type_name2();
2811 }
2812 else {
2813 title += "<null>";
2814 }
2815 write_common_header_info(os,fn,title.c_str());
2816
2817 // ================================================
2818 // Write out the package/namespace path:
2819 // ================================================
2820 if( stmt ) {
2821 os << "<table border=0 width=\"100%\"><tr><td align=left>\n";
2822 statement::base::stmts_t parents;
2823 stmt->get_parents(parents);
2824 if( parents.size() ) {
2825 statement::base::stmts_itr_t itr = parents.begin();
2826 statement::base* parent = *itr;
2827
2828 // If the user specfied -rooturl on the command line,
2829 // output it.
2830 if( m_sw.rooturl().size() ) {
2831 os << "<a href=\"" << m_sw.rooturl() << "\" target=_top>Home</a>\n";
2832 os << " :: ";
2833 }
2834
2835 // Now write out the path.
2836 write_link(os,parent);
2837 os << "\n";
2838 itr++;
2839 for(;itr!=parents.end();++itr) {
2840 parent = *itr;
2841 os << " :: ";
2842 write_link(os,parent);
2843 os << "\n";
2844 }
2845 }
2846 else {
2847 // This is the root.
2848 // Write out the Home link.
2849 if( m_sw.rooturl().size() ) {
2850 os << "<a href=\"" << m_sw.rooturl() << "\" target=_top>Home</a>\n";
2851 }
2852 }
2853 os << "</td><td align=right>";
2854 string url;
2855 string link_name = m_sw.html() + "ccdoc.class_summary.html";
2856 make_file_url(url,link_name);
2857 os << "<a href=\"" << url << "\">"
2858 << "classes</a></td></tr></table>\n";
2859 }
2860 }
2861 // ================================================================
2862 // Make the absolute path.
2863 // ================================================================
make_abs_path(statement::base * stmt,string & link) const2864 void ccdoc::phase3::html::make_abs_path(statement::base* stmt,
2865 string& link) const
2866 {
2867 int j = 0;
2868 statement::base::stmts_t parents;
2869 stmt->get_parents(parents);
2870 if( parents.size() ) {
2871 statement::base::stmts_itr_t itr = parents.begin();
2872 ++itr; // skip the root
2873 for(;itr!=parents.end();++itr,++j) {
2874 if( j )
2875 link += "::";
2876 link += (*itr)->get_id();
2877 }
2878 }
2879 if( j )
2880 link += "::";
2881 link += stmt->get_id();
2882 }
2883 // ================================================================
2884 // Make relative path.
2885 // ================================================================
make_rel_path(statement::base * parent,statement::base * stmt,string & link) const2886 void ccdoc::phase3::html::make_rel_path(statement::base* parent,
2887 statement::base* stmt,
2888 string& link) const
2889 {
2890 int j = 0;
2891 statement::base::stmts_t parents;
2892 stmt->get_parents(parents);
2893 if( parents.size() ) {
2894 statement::base::stmts_itr_t itr = parents.begin();
2895 ++itr; // skip the root
2896 // Skip until we find the relative top.
2897 for(;itr!=parents.end();++itr) {
2898 if( *itr == parent ) {
2899 // This is the parent,
2900 // point to the child.
2901 ++itr;
2902 break;
2903 }
2904 }
2905 for(;itr!=parents.end();++itr,++j) {
2906 if( j )
2907 link += "::";
2908 link += (*itr)->get_id();
2909 }
2910 }
2911 if( j )
2912 link += "::";
2913 link += stmt->get_id();
2914 }
2915 // ================================================================
2916 // Find and write out a links.
2917 // ================================================================
find_and_write_links(ostream & os,const char * in_link,const char * in_link_id,statement::base * scope)2918 unsigned ccdoc::phase3::html::find_and_write_links(ostream& os,
2919 const char* in_link,
2920 const char* in_link_id,
2921 statement::base* scope)
2922 {
2923 // Nothing is written if there is no valid link.
2924 unsigned count = 0;
2925 if( in_link && in_link_id ) {
2926 string link = in_link;
2927 // Check for a leading # as in:
2928 // {@link #Fct}
2929 if( in_link[0] == '#' ) {
2930 // Issue 0092:
2931 if( !scope )
2932 return count;
2933 scope->get_hier_id_no_pkgs(link);
2934 if( link.size() )
2935 link += "::";
2936 link += &in_link[1]; // strip off the leading '#'
2937 }
2938 statement::base::stmts_t stmts;
2939 m_db.get_stmt_no_pkgs(link,stmts);
2940 if( stmts.size() ) {
2941 statement::base::stmts_t output_stmts;
2942 statement::base::stmts_itr_t itr1 = stmts.begin();
2943 for(;itr1!=stmts.end();++itr1) {
2944 statement::base* stmt = *itr1;
2945 if( stmt->get_type() != statement::base::STMT_CLASS_END &&
2946 stmt->get_type() != statement::base::STMT_NAMESPACE_END &&
2947 stmt->get_type() != statement::base::STMT_STRUCT_END &&
2948 stmt->get_type() != statement::base::STMT_UNION_END ) {
2949 if( ignore_contents_stmt(stmt) == false )
2950 output_stmts.push_back(stmt);
2951 }
2952 }
2953 count = output_stmts.size();
2954 write_links(os,output_stmts,in_link_id);
2955 }
2956 }
2957 return count;
2958 }
2959 // ================================================================
2960 // Write out multiple links to the same reference in a separate
2961 // file.
2962 // ================================================================
write_links(ostream & os,const statement::base::stmts_t & stmts,const char * link_name)2963 void ccdoc::phase3::html::write_links(ostream& os,
2964 const statement::base::stmts_t& stmts,
2965 const char* link_name)
2966 {
2967 if( stmts.size() == 0 || link_name == 0 )
2968 return;
2969 if( stmts.size() == 1 ) {
2970 write_link(os,stmts[0],link_name);
2971 return;
2972 }
2973
2974 // Issue 0111
2975 // Issue 0083
2976 // First generate the new HTML file name.
2977 // Generate a unique file name for the multiple
2978 // links file so that they can be re-used.
2979 string fn = m_sw.html() + "ccdoc";
2980 const statement::base* stmt = stmts[0];
2981 statement::base::stmts_t parents;
2982 stmt->get_parents(parents);
2983 if(parents.size()) {
2984 statement::base::stmts_itr_t itr = parents.begin();
2985
2986 // Handle the first argument as a special case.
2987 // We don't want the '@' sign in the file name.
2988 fn += ".";
2989 if( m_sw.default_root() == (*itr)->get_id() ) {
2990 fn += "root"; // strip of the leading @ for the file name.
2991 }
2992 else {
2993 fn += format_name( (*itr)->get_id() );
2994 }
2995 ++itr;
2996 for(;itr!=parents.end();++itr) {
2997 fn += ".";
2998 fn += format_name( (*itr)->get_id() );
2999 }
3000 // Tack on the statement id.
3001 fn += ".";
3002 fn += format_name( stmt->get_id() );
3003 }
3004 else {
3005 // This is the root package statement.
3006 // Handle the first argument as a special case.
3007 // We don't want the '@' sign in the file name.
3008 fn += ".";
3009 if( m_sw.default_root() == stmt->get_id() ) {
3010 fn += "root"; // strip of the leading @ for the file name.
3011 }
3012 else {
3013 fn += format_name( stmt->get_id() );
3014 }
3015 }
3016 fn += ".xrf.html";
3017
3018 // Make the url.
3019 string url;
3020 make_file_url(url,fn);
3021
3022 // Now write out the link to this file.
3023 // Use italics as a visual cue to indicate that there are multiple
3024 // links.
3025 os << "<a href=\"" << url << "\">" << link_name << "</a>";
3026
3027 // See whether the file exists.
3028 bool exists = true;
3029 {
3030 ifstream is(fn.c_str());
3031 if(!is) {
3032 exists = false;
3033 }
3034 }
3035
3036 // If the link file doesn't exist, create it.
3037 if( !exists ) {
3038 ofstream os1(fn.c_str());
3039 if(!os) {
3040 throw ccdoc::exceptions::unwriteable_output_file(__FILE__,
3041 __LINE__,
3042 fn.c_str());
3043 }
3044 string title;
3045 title = "ccdoc xrf links for ";
3046 title += link_name;
3047 write_common_header_info(os1,fn,title.c_str());
3048
3049 // Populate the file.
3050 os1 << "<center>\n";
3051 os1 << "<h3>Multiply defined links for " << link_name << "</h3>\n";
3052 os1 << "<table border=1 cellspacing=1 cellpadding=2>";
3053 os1 << "<tr>";
3054 os1 << "<th>Link</th>"
3055 << "<th>Name</th>"
3056 << "<th>Type</th>"
3057 << "<th>Source</th>"
3058 << "<th>Short Description</th>";
3059 os1 << "</tr>\n";
3060 statement::base::stmts_citr_t itr = stmts.begin();
3061 for(;itr!=stmts.end();++itr) {
3062 statement::base* stmt = *itr;
3063
3064 // Link
3065 os1 << "<tr><td>";
3066 write_link(os1,stmt,link_name);
3067
3068 // Name
3069 os1 << "</td><td>";
3070 string id;
3071 stmt->get_hier_id_no_pkgs(id);
3072 os1 << id;
3073
3074 // Type
3075 os1 << "</td><td>";
3076 os1 << stmt->get_type_name2();
3077
3078 // Path
3079 os1 << "</td><td>";
3080 string path;
3081 write_ccdoc_src_info(path,stmt);
3082 if( path.size() )
3083 os1 << path;
3084
3085 // Short description.
3086 os1 << "</td><td>\n";
3087 write_short_desc(os1,stmt);
3088
3089 os1 << "</td></tr>\n";
3090 }
3091 os1 << "</table>\n";
3092 os1 << "</center>\n";
3093
3094 write_common_trailer_info(os1);
3095 }
3096 }
3097 // ================================================================
3098 // Write out a link.
3099 // ================================================================
write_link(ostream & os,const statement::base * stmt,const char * link_name)3100 void ccdoc::phase3::html::write_link(ostream& os,
3101 const statement::base* stmt,
3102 const char* link_name)
3103 {
3104 if( stmt ) {
3105 // There are three cases that have to be handled here:
3106 //
3107 // Case 1: The statement is an object in a standalone file.
3108 // Case 2: The statement is a tag in an existing file.
3109 // Case 3: A package with a user defined URL.
3110 //
3111 // Case 2 occurs when the stmt is not a class and the parent is
3112 // not a namespace or a package.
3113 string url;
3114 string tag;
3115 if( statement::base::STMT_PACKAGE == stmt->get_type() &&
3116 stmt->get_comment() ) {
3117 // Issue 0025
3118 // The user specified a custom URL. Use the package name
3119 // along with the users URL.
3120 // The URL is obtained from the associated comment.
3121 statement::comment doc(stmt->get_comment());
3122 url = doc.get_pkgdoc_url();
3123 }
3124 if( url.size() == 0 ) {
3125 if ( make_file_url(url,stmt) ) {
3126 string id;
3127 make_tag_id(stmt,id);
3128 tag = "#" + id;
3129 }
3130 }
3131 // Write out the link.
3132 os << "<a href=\"" << url << tag << "\">";
3133 if( link_name ) {
3134 write_html_formatted_string(os,link_name);
3135 }
3136 else {
3137 write_html_formatted_string(os,stmt->get_id());
3138 }
3139 os << "</a>";
3140 }
3141 }
3142 // ================================================================
3143 // write meta info
3144 // ================================================================
write_meta(ostream & os,const char * name,const char * content)3145 void ccdoc::phase3::html::write_meta(ostream& os,
3146 const char* name,
3147 const char* content)
3148 {
3149 os << "<meta name=\""
3150 << name
3151 << "\" content=\""
3152 << content
3153 << "\">\n";
3154 }
3155 // ================================================================
3156 // write common trailer info
3157 // ================================================================
write_common_trailer_info(ostream & os)3158 void ccdoc::phase3::html::write_common_trailer_info(ostream& os)
3159 {
3160 os << "<a name=ccdoc_bottom></a>\n"
3161 << "<hr>\n";
3162 if(m_trailer.size()) {
3163 // The user specified a customized trailer, use it.
3164 os << m_trailer << endl;
3165 }
3166 else {
3167 // Output the default message.
3168 // Note that the copyright is not displayed here because
3169 // I don't own the contents of the page.
3170 os << "<center>\n"
3171 << "<p>\n"
3172 << "<font size=\"-1\">\n"
3173 << "Created " << date_time() << ".\n"
3174 << "<br>\n"
3175 << "This documentation was generated automatically by\n"
3176 << "<br>\n"
3177 << m_sw.version() << ".\n"
3178 << "<br>\n"
3179 << "Click "
3180 << "<a href=\"mailto:joe@joelinoff.com,jdl@xilinx.com"
3181 << "?subject="
3182 << "Bug report or feature request for "
3183 << m_sw.version()
3184 << "\">here</a>"
3185 << " to submit a bug report or feature request for ccdoc.\n"
3186 << "<br>\n"
3187 << "Click <a href=\"#ccdoc_top\">here</a>"
3188 << " to return to the top of the page.\n"
3189 << "</font>\n"
3190 << "</center>\n"
3191 ;
3192 }
3193 os << "</body>\n"
3194 << "</html>\n"
3195 ;
3196 }
3197 // ================================================================
3198 // Write the extends clause for classes and structs.
3199 // ================================================================
write_extends_clause(ostream & os,statement::base * stmt)3200 void ccdoc::phase3::html::write_extends_clause(ostream& os,
3201 statement::base* stmt)
3202 {
3203 if( stmt ) {
3204 // Write the extends clause.
3205 // extends <class> as <public|protected|private>
3206 bool first = true;
3207 string extends_prefix = " extends ";
3208 const statement::base::cstrs_t& vec1 = stmt->get_tokens();
3209 statement::base::cstrs_citr_t itr1 = vec1.begin();
3210 for(;itr1!=vec1.end();++itr1) {
3211 string token = *itr1;
3212 if( token == ":" ) {
3213 itr1++;
3214 break;
3215 }
3216 }
3217 if( itr1!=vec1.end() ) {
3218 // This is a derived class of the form:
3219 // class A : ... { ... };
3220 statement::base::cstrs_citr_t end = itr1;
3221 while( end!=vec1.end() ) {
3222 string id;
3223 statement::base::strs_t access;
3224 string token;
3225
3226 // ================================================
3227 // Get the type and the access specifiers.
3228 // Do this the easy way.
3229 // ================================================
3230 bool found_id = false;
3231 int depth = 0;
3232 for(;end!=vec1.end();++end) {
3233 token = *end;
3234 if( !found_id ) {
3235 if( token == "virtual" ||
3236 token == "public" ||
3237 token == "protected" ||
3238 token == "private" ) {
3239 access.push_back(token);
3240 continue;
3241 }
3242 found_id = true;
3243 }
3244 if( found_id ) {
3245 if( token == "<" ) {
3246 // This handles cases like:
3247 // class A : public foo<My1,My2> ;
3248 // class A : public foo<My1,My2<XX> > ;
3249 depth++;
3250 }
3251 else if( token == ">" ) {
3252 depth--;
3253 }
3254 else if( depth == 0 ) {
3255 if( token == "," ) {
3256 // Output the extends information.
3257 ++end;
3258 break;
3259 }
3260 }
3261 id += token;
3262 }
3263 }
3264
3265 // ================================================
3266 // At this point the id and access vector are set.
3267 // ================================================
3268 // Write out the extends clause.
3269 if( !first )
3270 os << "<br>";
3271 if( first )
3272 first = false;
3273 os << extends_prefix;
3274
3275 // ================================================
3276 // Write out the link.
3277 // ================================================
3278 statement::base::stmts_t id_class_stmts;
3279 load_extend_classes(id,id_class_stmts,stmt);
3280 if( id_class_stmts.size() == 0 ) {
3281 os << "<font color=red>"
3282 << format_string_for_html(id)
3283 << "</font>";
3284 // Issue 109:
3285 // The error condition for this can be created as follows:
3286 // class Test : public Undefined {
3287 // public:
3288 // Test();
3289 // ~Test();
3290 // };
3291 s_log.warning()
3292 << "UNDEF: Undefined reference in extends clause for '"
3293 << id
3294 << "' in "
3295 << stmt->get_type_name2()
3296 << " '"
3297 << stmt->get_id()
3298 << "' at line "
3299 << stmt->get_lineno()
3300 << " in file "
3301 << stmt->get_file()
3302 << "\n"
3303 << s_log.enable();
3304 }
3305 else if( id_class_stmts.size() == 1 ) {
3306 write_link(os,id_class_stmts[0],id.c_str());
3307 }
3308 else {
3309 // There are too many links.
3310 // Write all of the links.
3311 statement::base::stmts_itr_t sitr = id_class_stmts.begin();
3312 os << "{ ";
3313 for(;sitr!=id_class_stmts.end();++sitr) {
3314 statement::base* id_stmt = *sitr;
3315 if( sitr != id_class_stmts.begin() )
3316 os << ", ";
3317 write_link(os,id_stmt,id.c_str());
3318 }
3319 os << " }";
3320 }
3321
3322 // ================================================
3323 // Write out the "as" clause.
3324 // ================================================
3325 os << " as";
3326 if( access.size() ) {
3327 statement::base::strs_itr_t titr = access.begin();
3328 for(;titr!=access.end();++titr) {
3329 os << " " << *titr;
3330 }
3331 }
3332 else {
3333 // 11.2 ISO/IEC 14882:1998(E)
3334 if( stmt->get_type() == statement::base::STMT_CLASS_BEGIN )
3335 os << " private";
3336 else if( stmt->get_type() == statement::base::STMT_STRUCT_BEGIN )
3337 os << " public";
3338 else {
3339 os << " <font color=red>unknown</font>";
3340 // Issue 109:
3341 // TODO: Don't know how to trigger this for testing.
3342 s_log.warning()
3343 << "UNDEF: Undefined type '"
3344 << stmt->get_type_name2()
3345 << " for '"
3346 << stmt->get_id()
3347 << "' at line "
3348 << stmt->get_lineno()
3349 << " in file "
3350 << stmt->get_file()
3351 << "\n"
3352 << s_log.enable();
3353 }
3354 }
3355 os << "\n";
3356 }
3357 os << "<p>\n";
3358 }
3359 }
3360 }
3361 // ================================================================
3362 // Write out the friends info
3363 // ================================================================
write_friends_info(ostream & os,statement::base * stmt)3364 void ccdoc::phase3::html::write_friends_info(ostream& os,
3365 statement::base* stmt)
3366 {
3367 statement::base* scope = stmt;
3368 statement::base::stmts_t friends;
3369 statement::base::stmts_t& children = stmt->get_children();
3370 statement::base::stmts_itr_t itr = children.begin();
3371 for(;itr!=children.end();++itr) {
3372 if( (*itr)->get_type() == statement::base::STMT_FRIEND_CLASS ||
3373 (*itr)->get_type() == statement::base::STMT_FRIEND_FUNCTION ) {
3374 friends.push_back(*itr);
3375 }
3376 }
3377 if( friends.size() ) {
3378 if( friends.size() == 1 ) {
3379 os << "<dt><b>Friend:</b></dt><dd><table cellspacing=4>\n";
3380 }
3381 else {
3382 os << "<dt><b>Friends:</b></dt><dd><table cellspacing=4>\n";
3383 }
3384 itr = friends.begin();
3385 for(;itr!=friends.end();++itr) {
3386 statement::base* f = *itr;
3387
3388 os << "<tr>\n";
3389
3390 os << "<td align=left valign=top>\n";
3391 if( f->get_type() == statement::base::STMT_FRIEND_CLASS )
3392 os << "<font color=green><b>class</b></font>";
3393 else if( f->get_type() == statement::base::STMT_FRIEND_FUNCTION )
3394 os << "<font color=green><b>function</b></font>";
3395 os << "</td>\n";
3396
3397 os << "<td align=left valign=top>\n";
3398 statement::base::stmts_t matches;
3399 string id = f->get_id();
3400 m_db.get_stmt_no_pkgs(id,matches);
3401 if( matches.size() == 0 ) {
3402 // Issue 0064
3403 // The name was not found, try looking in the namespace
3404 // of the parent.
3405 if(stmt->get_parent()) {
3406 stmt->get_parent()->get_hier_id_no_pkgs(id);
3407 id += "::";
3408 id += f->get_id();
3409 m_db.get_stmt_no_pkgs(id,matches);
3410 }
3411 }
3412 if( matches.size() == 1 ) {
3413 //write_link(os,matches[0],f->get_id());
3414 write_friends_link(os,matches[0],f);
3415 }
3416 else if( matches.size() > 1 ) {
3417 // Filter to match the type.
3418 statement::base::stmts_t filter_matches;
3419 statement::base::stmts_itr_t mitr = matches.begin();
3420 for(;mitr!=matches.end();++mitr) {
3421 if( f->get_type() == statement::base::STMT_FRIEND_CLASS ) {
3422 if( (*mitr)->get_type() == statement::base::STMT_CLASS_BEGIN ||
3423 (*mitr)->get_type() == statement::base::STMT_STRUCT_BEGIN ) {
3424 filter_matches.push_back( *mitr );
3425 break; // avoid length searches for now
3426 }
3427 }
3428 else if( f->get_type() == statement::base::STMT_FRIEND_FUNCTION ) {
3429 if( (*mitr)->get_type() == statement::base::STMT_FUNCTION ||
3430 (*mitr)->get_type() == statement::base::STMT_FUNCTION_OPERATOR ||
3431 (*mitr)->get_type() == statement::base::STMT_METHOD_CONSTRUCTOR ||
3432 (*mitr)->get_type() == statement::base::STMT_METHOD_DESTRUCTOR ||
3433 (*mitr)->get_type() == statement::base::STMT_METHOD_OPERATOR ||
3434 (*mitr)->get_type() == statement::base::STMT_METHOD ) {
3435 filter_matches.push_back( *mitr );
3436 break; // avoid length searches for now
3437 }
3438 }
3439 }
3440 if( filter_matches.size() ) {
3441 //write_link(os,filter_matches[0],f->get_id());
3442 write_friends_link(os,filter_matches[0],f);
3443 }
3444 else {
3445 //write_link(os,matches[0],f->get_id());
3446 write_friends_link(os,matches[0],f);
3447 }
3448 }
3449 else {
3450 write_friends_link(os,0,f);
3451 // Issue 109:
3452 // The error condition for this can be created as follows:
3453 // class Foo { friend class Undefined; }
3454 s_log.warning()
3455 << "UNDEF: Undefined friend reference to '"
3456 << f->get_id()
3457 << "' in "
3458 << stmt->get_type_name2()
3459 << " '"
3460 << stmt->get_id()
3461 << "' at line "
3462 << f->get_lineno()
3463 << " in file "
3464 << f->get_file()
3465 << "\n"
3466 << s_log.enable();
3467 }
3468 os << "</td>\n";
3469
3470 os << "<td align=left valign=top>\n";
3471 if( f->get_comment() ) {
3472 // Special case:
3473 // Only the descriptions are written for friends.
3474 statement::comment doc(f->get_comment());
3475 write_ccdoc_desc_info(os,doc.get_short_desc(),scope,stmt);
3476 if(doc.get_short_desc().size() && doc.get_long_desc().size())
3477 os << "<p>\n";
3478 write_ccdoc_desc_info(os,doc.get_long_desc(),scope,stmt);
3479 }
3480 else {
3481 os << m_sw.rptdefsd();
3482 }
3483 os << "</td>\n";
3484 os << "</tr>\n";
3485 }
3486 os << "</table>\n";
3487 os << "</dd>\n";
3488 }
3489 }
3490 // ================================================================
3491 // Write out the friends link
3492 // ================================================================
write_friends_link(ostream & os,statement::base * link_stmt,statement::base * friend_stmt)3493 void ccdoc::phase3::html::write_friends_link(ostream& os,
3494 statement::base* link_stmt,
3495 statement::base* friend_stmt)
3496 {
3497 if( link_stmt ) {
3498 write_link(os,link_stmt,friend_stmt->get_id());
3499 }
3500 else {
3501 os << "<font color=red>"
3502 << format_string_for_html(friend_stmt->get_id())
3503 << "</font>";
3504 }
3505 // Now write out the rest of the statement.
3506 const statement::base::cstrs_t& tokens = friend_stmt->get_tokens();
3507 statement::base::cstrs_citr_t itr = tokens.begin();
3508 for(;itr!=tokens.end();++itr) {
3509 string token = *itr;
3510 if( token == friend_stmt->get_id() ) {
3511 ++itr;
3512 break;
3513 }
3514 }
3515 for(;itr!=tokens.end();++itr) {
3516 string token = *itr;
3517 write_code_subsection_token(os,friend_stmt,token);
3518 }
3519 }
3520 // ================================================================
3521 // Write out the ccdoc information.
3522 // ================================================================
write_ccdoc_info(ostream & os,statement::base * stmt,bool author_required,bool version_required,bool inherited)3523 void ccdoc::phase3::html::write_ccdoc_info(ostream& os,
3524 statement::base* stmt,
3525 bool author_required,
3526 bool version_required,
3527 bool inherited)
3528 {
3529 statement::base* scope = stmt->get_parent();
3530 if( stmt->get_comment() ) {
3531 statement::comment doc(stmt->get_comment());
3532
3533 // Short description.
3534 write_ccdoc_desc_info(os,doc.get_short_desc(),scope,stmt);
3535
3536 if(doc.get_short_desc().size() && doc.get_long_desc().size())
3537 os << "<p>\n";
3538
3539 // Long description.
3540 write_ccdoc_desc_info(os,doc.get_long_desc(),scope,stmt);
3541
3542 os << "<dl>\n";
3543
3544 // Inherited from
3545 if( inherited && stmt->get_parent() )
3546 write_inherited_from_info(os,stmt);
3547
3548 // Source file
3549 write_ccdoc_src_info(os,stmt,scope);
3550
3551 // Author
3552 string id = "Author";
3553 if(doc.get_authors().size()>1)
3554 id = "Authors";
3555 if( author_required )
3556 write_ccdoc_directive_info(os,id.c_str(),doc.get_authors(),m_sw.rptdefa(),scope,stmt,true);
3557 else
3558 write_ccdoc_directive_info(os,id.c_str(),doc.get_authors(),0,scope,stmt,true);
3559
3560 // Version
3561 if( version_required )
3562 write_ccdoc_directive_info(os,"Version",doc.get_version(),m_sw.rptdefv(),scope,stmt);
3563 else
3564 write_ccdoc_directive_info(os,"Version",doc.get_version(),0,scope,stmt);
3565
3566 // Since
3567 // Issue 0082: 10/18/01 bzoe
3568 write_ccdoc_directive_info(os,"Since",doc.get_since(),0,scope,stmt);
3569
3570 // Deprecated
3571 write_ccdoc_directive_info(os,"Deprecated",doc.get_deprecated(),0,scope,stmt,false);
3572
3573 // Params
3574 write_ccdoc_param_directive_info(os,doc.get_params(),scope,stmt);
3575
3576 // Returns
3577 write_ccdoc_directive_info(os,"Returns",doc.get_returns(),0,scope,stmt,false);
3578
3579 // Exceptions
3580 write_ccdoc_exception_directive_info(os,doc.get_exceptions(),scope,stmt);
3581
3582 // See
3583 write_ccdoc_see_directive_info(os,doc.get_sees(),stmt);
3584
3585 // Todo (Issue 0120)
3586 write_ccdoc_directive_info(os,"Todo",doc.get_todo(),0,scope,stmt,false);
3587
3588 // The following directives are not output in HTML
3589 // @pkg
3590 // @pkgdoc
3591 // @suffix
3592 os << "</dl>\n";
3593 }
3594 else {
3595 // What do we do with entities that do not have a ccdoc
3596 // comment?
3597 // Write out the source information and the author stuff.
3598 statement::base::strs_t empty_vec;
3599 string empty_str;
3600
3601 if( stmt->get_type() == statement::base::STMT_PACKAGE ) {
3602 // Special case handling for packages with no comments.
3603 // Packages don't have source.
3604 if( m_sw.rptdpd() == true ) {
3605 // Report package comments if -rptdpd was specified, otherwise
3606 // don't.
3607 os << m_sw.rptdefsd();
3608 }
3609 if( inherited || author_required || version_required ) {
3610 os << "<dl>\n";
3611 if( inherited && stmt->get_parent() )
3612 write_inherited_from_info(os,stmt);
3613 if( author_required )
3614 write_ccdoc_directive_info(os,"Author",empty_vec,m_sw.rptdefa(),scope,stmt,true);
3615 if( version_required )
3616 write_ccdoc_directive_info(os,"Version",empty_str,m_sw.rptdefv(),scope,stmt);
3617 os << "</dl>\n";
3618 }
3619 return;
3620 }
3621
3622 // Tell them that it is not documented.
3623 if(stmt->get_lineno() == 0 ) {
3624 // Packages never have line numbers.
3625 // Lineno zero flags the fact that it
3626 // was automatically generated by the
3627 // compiler.
3628 os << m_sw.rptdefasd();
3629 }
3630 else {
3631 os << m_sw.rptdefsd();
3632 }
3633
3634 os << "<dl>\n";
3635 if( inherited && stmt->get_parent() )
3636 write_inherited_from_info(os,stmt);
3637 write_ccdoc_src_info(os,stmt,scope);
3638 if( author_required )
3639 write_ccdoc_directive_info(os,"Author",empty_vec,m_sw.rptdefa(),scope,stmt,true);
3640 if( version_required )
3641 write_ccdoc_directive_info(os,"Version",empty_str,m_sw.rptdefv(),scope,stmt);
3642 os << "</dl>\n";
3643 }
3644 }
3645 // ================================================================
3646 // Write out the source file information.
3647 // ================================================================
write_ccdoc_src_info(ostream & os,statement::base * stmt,statement::base * scope)3648 void ccdoc::phase3::html::write_ccdoc_src_info(ostream& os,
3649 statement::base* stmt,
3650 statement::base* scope)
3651 {
3652 string path;
3653 if( write_ccdoc_src_info(path,stmt) ) {
3654 write_ccdoc_directive_info(os,"Source",path,0,scope,stmt);
3655 }
3656 }
3657 // ================================================================
3658 // Write out the source file information.
3659 // ================================================================
write_ccdoc_src_info(string & path,statement::base * stmt)3660 bool ccdoc::phase3::html::write_ccdoc_src_info(string& path,
3661 statement::base* stmt)
3662 {
3663 // Source file
3664 if(stmt &&
3665 stmt->get_type() != statement::base::STMT_PACKAGE ) { // Issue 0027
3666 string file;
3667 if(stmt->get_file())
3668 file = stmt->get_file();
3669 else
3670 file = "unknown";
3671 if( stmt->get_file() && m_sw.srcurl().size() ) {
3672 // Build an anchor reference to the source file.
3673 string urlfn = stmt->get_file();
3674 if( m_sw.dospaths() ) {
3675 // Convert the DOS backslashes to forward slashes for HTML.
3676 replace(urlfn.begin(),urlfn.end(),'\\','/');
3677 }
3678 if( urlfn.size() ) {
3679 path = "<a href=\"" + m_sw.srcurl() + urlfn + "\">" + file + "</a>";
3680 }
3681 }
3682 else {
3683 path = file;
3684 }
3685 if( path.size() ) {
3686 // Don't append the line numbers of zero. They are meaningless.
3687 if( stmt->get_lineno() ) {
3688 char nbuf[32];
3689 sprintf(nbuf,"%d",stmt->get_lineno()); // Issue: 0056
3690 path += ":";
3691 path += nbuf;
3692 }
3693 }
3694 return true;
3695 }
3696 return false;
3697 }
3698 // ================================================================
3699 // Write out the ccdoc description information.
3700 // Dereference the @link and @$ directives.
3701 // ================================================================
write_ccdoc_desc_info(ostream & os,const statement::base::strs_t & vec,statement::base * scope,statement::base * stmt)3702 void ccdoc::phase3::html::write_ccdoc_desc_info(ostream& os,
3703 const statement::base::strs_t& vec,
3704 statement::base* scope,
3705 statement::base* stmt)
3706 {
3707 statement::base::strs_citr_t itr = vec.begin();
3708 for(;itr!=vec.end();++itr) {
3709 write_ccdoc_line_info(os,itr,vec.end(),scope,stmt);
3710 }
3711 }
3712 // ================================================================
3713 // Write out link info in each comment line.
3714 // ================================================================
write_ccdoc_line_info(ostream & os,statement::base::strs_citr_t & itr,statement::base::strs_citr_t itr_end,statement::base * scope,statement::base * stmt)3715 void ccdoc::phase3::html::write_ccdoc_line_info(ostream& os,
3716 statement::base::strs_citr_t& itr,
3717 statement::base::strs_citr_t itr_end,
3718 statement::base* scope,
3719 statement::base* stmt)
3720 {
3721 const string& line = *itr;
3722 if( line == "@link" ) {
3723 // This is a link line.
3724 if( ++itr == itr_end ) {
3725 os << line << "\n";
3726 return;
3727 }
3728 string link = *itr;
3729 if( ++itr == itr_end ) {
3730 os << line << "\n"
3731 << link << "\n";
3732 return;
3733 }
3734 // Issue 0088.
3735 string id = *itr;
3736 if( id == link && link[0] == '#' ) {
3737 // Issue 0125
3738 id.erase(0,1); // erase the 1st character
3739 }
3740 if( !find_and_write_links(os,link.c_str(),id.c_str(),scope) ) {
3741 os << "<font color=red>"
3742 << format_string_for_html(id)
3743 << "</font>";
3744 // Issue 109:
3745 // The error condition for this can be created as follows:
3746 // /**
3747 // * See {@link Undefined} for more details.
3748 // */
3749 // class Foo { int m_a; };
3750 s_log.warning()
3751 << "UNDEF: Undefined {@link ...} reference to '"
3752 << id
3753 << "' in ccdoc comment at line "
3754 << stmt->get_lineno()
3755 << " in file "
3756 << stmt->get_file()
3757 << "\n"
3758 << s_log.enable();
3759 }
3760 }
3761 else if( line == " " ) {
3762 // This is how the scanner tells us to insert a
3763 // paragraph separator.
3764 os << "<p>\n";
3765 }
3766 else {
3767 os << line << "\n";
3768 }
3769 }
3770 // ================================================================
3771 // Write out the ccdoc directive information.
3772 // ================================================================
write_ccdoc_param_directive_info(ostream & os,const statement::base::strss_t & vecvec,statement::base * scope,statement::base * stmt)3773 void ccdoc::phase3::html::write_ccdoc_param_directive_info(ostream& os,
3774 const statement::base::strss_t& vecvec,
3775 statement::base* scope,
3776 statement::base* stmt)
3777 {
3778 if( vecvec.size() == 0 ) {
3779 return;
3780 }
3781 string name = "Param";
3782 if( vecvec.size() > 1 ) {
3783 name = "Params";
3784 }
3785 os << "<dt><b>" << name << ":</b></dt><dd><table cellspacing=4>\n";
3786 statement::base::strss_citr_t i = vecvec.begin();
3787 statement::base::strss_citr_t e = vecvec.end();
3788 for(;i!=e;++i) {
3789 const statement::base::strs_t& vec = *i;
3790 statement::base::strs_citr_t i1 = vec.begin();
3791 os << "<tr><td align=left valign=top><i>";
3792 write_ccdoc_line_info(os,i1,vec.end(),scope,stmt);
3793 os << "</i></td><td align=left valign=top>";
3794 for(++i1;i1!=vec.end();++i1) {
3795 write_ccdoc_line_info(os,i1,vec.end(),scope,stmt);
3796 }
3797 os << "</td></tr>\n";
3798 }
3799 os << "</table></dd>\n";
3800 }
3801 // ================================================================
3802 // Write out the ccdoc exception directive information.
3803 // ================================================================
write_ccdoc_exception_directive_info(ostream & os,const statement::base::strss_t & vecvec,statement::base * scope,statement::base * stmt)3804 void ccdoc::phase3::html::write_ccdoc_exception_directive_info(ostream& os,
3805 const statement::base::strss_t& vecvec,
3806 statement::base* scope,
3807 statement::base* stmt)
3808 {
3809 if( vecvec.size() == 0 ) {
3810 return;
3811 }
3812 string name = "Exception";
3813 if( vecvec.size() > 1 ) {
3814 name = "Exceptions";
3815 }
3816 os << "<dt><b>" << name << ":</b></dt><dd><table cellspacing=4>\n";
3817 statement::base::strss_citr_t i = vecvec.begin();
3818 statement::base::strss_citr_t e = vecvec.end();
3819 for(;i!=e;++i) {
3820 const statement::base::strs_t& vec = *i;
3821 statement::base::strs_citr_t i1 = vec.begin();
3822 os << "<tr><td align=left valign=top><i>";
3823 // Issue 0087.
3824 // Write out the exception as a link, if possible.
3825 string id = *i1;
3826 if( !find_and_write_links(os,id.c_str(),id.c_str(),scope) ) {
3827 os << format_string_for_html(id);
3828 }
3829 os << "</i></td><td align=left valign=top>";
3830 // Write out the rest of the exception info.
3831 for(++i1;i1!=vec.end();++i1) {
3832 write_ccdoc_line_info(os,i1,vec.end(),scope,stmt);
3833 }
3834 os << "</td></tr>\n";
3835 }
3836 os << "</table></dd>\n";
3837 }
3838 // ================================================================
3839 // Write out the ccdoc directive information.
3840 // ================================================================
write_ccdoc_see_directive_info(ostream & os,const statement::base::strss_t & vecvec,statement::base * stmt)3841 void ccdoc::phase3::html::write_ccdoc_see_directive_info(ostream& os,
3842 const statement::base::strss_t& vecvec,
3843 statement::base* stmt)
3844 {
3845 if( vecvec.size() == 0 ) {
3846 return;
3847 }
3848 string name = "See Also";
3849 os << "<dt><b>" << name << ":</b></dt><dd>";
3850
3851 statement::base::strss_citr_t i = vecvec.begin();
3852 statement::base::strss_citr_t e = vecvec.end();
3853 for(int j=0;i!=e;++i,++j) {
3854 const statement::base::strs_t& vec = *i;
3855 statement::base::strs_citr_t i1 = vec.begin();
3856 string link = *i1;
3857 ++i1;
3858 string index = *i1;
3859 string name = link;
3860
3861 // Issue 0019
3862 if(link[0] == '<' ) {
3863 // Handle the special case where the user defined
3864 // an explicit link.
3865 // Just use what they specified.
3866 if(j)
3867 os << ", "; // Issue 0024
3868 os << link << "\n";
3869 continue;
3870 }
3871
3872 // Issue 0043.
3873 if( link[0] == '#' ) {
3874 // The parent defines the scope.
3875 const char* ps = link.c_str();
3876 name = &ps[1]; // strip of the leading '#"
3877 if( stmt->get_parent() )
3878 stmt->get_parent()->get_hier_id_no_pkgs(link);
3879 if( link.size() )
3880 link += "::";
3881 link += name;
3882 }
3883
3884 statement::base::stmts_t stmts;
3885 m_db.get_stmt_no_pkgs(link,stmts);
3886
3887 if(index != "*" ) {
3888 // Output the indexed reference.
3889 unsigned num = atoi(index.c_str());
3890 if( stmts.size() > num ) {
3891 statement::base* stmt = stmts[num];
3892 if(j)
3893 os << ", ";
3894 write_link(os,stmt,name.c_str());
3895 }
3896 else {
3897 if(j)
3898 os << ", ";
3899 // Issue 109:
3900 // The error condition for this can be created as follows:
3901 // /**
3902 // * @see Undefined
3903 // * @see Undefined 1
3904 // */
3905 // class Foo { int m_a; };
3906 if( stmts.size() == 0 ) {
3907 os << "<font color=red>"
3908 << format_string_for_html(name)
3909 << "</font>";
3910 s_log.warning()
3911 << "UNDEF: Undefined @see link to reference '"
3912 << name
3913 << "' in ccdoc comment at line "
3914 << stmt->get_lineno()
3915 << " in file "
3916 << stmt->get_file()
3917 << "\n"
3918 << s_log.enable();
3919 }
3920 else {
3921 if( num > 0 ) {
3922 os << "<font color=red>"
3923 << format_string_for_html(name)
3924 << "["
3925 << num
3926 << "]"
3927 << "</font>";
3928 }
3929 else {
3930 os << "<font color=red>"
3931 << format_string_for_html(name)
3932 << "</font>";
3933 }
3934 s_log.warning()
3935 << "UNDEF: Undefined @see link to index reference '"
3936 << name
3937 << "["
3938 << index
3939 << "]"
3940 << "' in ccdoc comment at line "
3941 << stmt->get_lineno()
3942 << " in file "
3943 << stmt->get_file()
3944 << "\n"
3945 << s_log.enable();
3946 }
3947 }
3948 }
3949 else {
3950 if( stmts.size() ) {
3951 // Output all of the references.
3952 statement::base::stmts_itr_t itr1 = stmts.begin();
3953 for(;itr1!=stmts.end();++itr1,++j) {
3954 statement::base* stmt = *itr1;
3955 if(j)
3956 os << ", ";
3957 write_link(os,stmt,name.c_str());
3958 }
3959 }
3960 else {
3961 if(j)
3962 os << ", ";
3963 os << "<font color=red>"
3964 << format_string_for_html(name)
3965 << "</font>";
3966 // Issue 109:
3967 // It is not clear that this can be triggered.
3968 // I think this is dead code.
3969 s_log.warning()
3970 << "UNDEF: Undefined @see link to '"
3971 << name
3972 << "' at line "
3973 << stmt->get_lineno()
3974 << " in file "
3975 << stmt->get_file()
3976 << "\n"
3977 << s_log.enable();
3978 }
3979 }
3980 }
3981
3982 os << "</dd>\n";
3983 }
3984 // ================================================================
3985 // Write out the inherited from info.
3986 // ================================================================
write_inherited_from_info(ostream & os,statement::base * stmt)3987 void ccdoc::phase3::html::write_inherited_from_info(ostream& os,
3988 statement::base* stmt)
3989 {
3990 os << "<dt><b>Inherited From:</b></dt><dd>";
3991 string id;
3992 stmt->get_parent()->get_hier_id_no_pkgs(id);
3993 write_link(os,stmt->get_parent(),id.c_str());
3994 os << "</dd>\n";
3995 }
3996 // ================================================================
3997 // Write out the ccdoc directive information.
3998 // ================================================================
write_ccdoc_directive_info(ostream & os,const char * name,const statement::base::strs_t & vec,const char * default_field,statement::base * scope,statement::base * stmt,bool commas)3999 void ccdoc::phase3::html::write_ccdoc_directive_info(ostream& os,
4000 const char* name,
4001 const statement::base::strs_t& vec,
4002 const char* default_field,
4003 statement::base* scope,
4004 statement::base* stmt,
4005 bool commas)
4006 {
4007 if( vec.size() == 0 && default_field == 0 ) {
4008 return;
4009 }
4010 os << "<dt><b>" << name << ":</b></dt><dd>";
4011 if( vec.size() == 0 ) {
4012 // There are no entries, output the default
4013 // value.
4014 os << default_field;
4015 }
4016 else {
4017 statement::base::strs_citr_t i = vec.begin();
4018 statement::base::strs_citr_t e = vec.end();
4019 if( i!=e ) {
4020 write_ccdoc_line_info(os,i,vec.end(),scope,stmt);
4021 }
4022 for(++i;i!=e;++i) {
4023 if( commas ) // issue 0095
4024 os << ", ";
4025 write_ccdoc_line_info(os,i,vec.end(),scope,stmt);
4026 }
4027 }
4028 os << "</dd>\n";
4029 }
4030 // ================================================================
4031 // Write out the ccdoc directive information.
4032 // ================================================================
write_ccdoc_directive_info(ostream & os,const char * name,const string & val,const char * default_field,statement::base * scope,statement::base * stmt)4033 void ccdoc::phase3::html::write_ccdoc_directive_info(ostream& os,
4034 const char* name,
4035 const string& val,
4036 const char* default_field,
4037 statement::base* scope,
4038 statement::base* stmt)
4039 {
4040 if( val.size() == 0 && default_field == 0 ) {
4041 return;
4042 }
4043 os << "<dt><b>" << name << ":</b></dt><dd>";
4044 if( val.size() == 0 ) {
4045 // There are no entries, output the default
4046 // value.
4047 os << default_field;
4048 }
4049 else {
4050 os << val;
4051 }
4052 os << "</dd>\n";
4053 }
4054 // ================================================================
4055 // Date and time.
4056 // ================================================================
4057 #include <time.h>
date_time() const4058 const char* ccdoc::phase3::html::date_time() const
4059 {
4060 static char tbuf[128];
4061 time_t ltime;
4062 ::time(<ime);
4063 ::strcpy(tbuf,::ctime(<ime));
4064
4065 // Strip off the new line.
4066 char* p = tbuf;
4067 const char* e = &tbuf[127]; // detect overflows
4068 for(;*p != '\n' && *p != 0 && p < e; *p++);
4069 *p = 0;
4070 return tbuf;
4071 }
4072
4073 // ================================================================
4074 // CrcTable
4075 // ================================================================
4076 unsigned ccdoc::phase3::html::checksum::m_crc_table[256] = {
4077 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
4078 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
4079 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
4080 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
4081 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
4082 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
4083 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
4084 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
4085 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
4086 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
4087 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
4088 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
4089 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
4090 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
4091 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
4092 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
4093 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
4094 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
4095 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
4096 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
4097 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
4098 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
4099 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
4100 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
4101 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
4102 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
4103 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
4104 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
4105 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
4106 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
4107 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
4108 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
4109 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
4110 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
4111 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
4112 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
4113 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
4114 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
4115 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
4116 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
4117 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
4118 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
4119 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
4120 };
4121