]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/boostdep/src/boostdep.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / tools / boostdep / src / boostdep.cpp
1
2 // boostdep - a tool to generate Boost dependency reports
3 //
4 // Copyright 2014-2017 Peter Dimov
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt
9
10 #define _CRT_SECURE_NO_WARNINGS
11
12 #include <boost/filesystem.hpp>
13 #include <boost/filesystem/fstream.hpp>
14 #include <string>
15 #include <iostream>
16 #include <fstream>
17 #include <vector>
18 #include <map>
19 #include <set>
20 #include <algorithm>
21 #include <climits>
22 #include <cstdlib>
23 #include <streambuf>
24 #include <sstream>
25
26 namespace fs = boost::filesystem;
27
28 // header -> module
29 static std::map< std::string, std::string > s_header_map;
30
31 // module -> headers
32 static std::map< std::string, std::set<std::string> > s_module_headers;
33
34 static std::set< std::string > s_modules;
35
36 static void scan_module_headers( fs::path const & path )
37 {
38 try
39 {
40 std::string module = path.generic_string().substr( 5 ); // strip "libs/"
41
42 std::replace( module.begin(), module.end(), '/', '~' );
43
44 s_modules.insert( module );
45
46 fs::path dir = path / "include";
47 size_t n = dir.generic_string().size();
48
49 fs::recursive_directory_iterator it( dir ), last;
50
51 for( ; it != last; ++it )
52 {
53 if( it->status().type() == fs::directory_file )
54 {
55 continue;
56 }
57
58 std::string p2 = it->path().generic_string();
59 p2 = p2.substr( n+1 );
60
61 s_header_map[ p2 ] = module;
62 s_module_headers[ module ].insert( p2 );
63 }
64 }
65 catch( fs::filesystem_error const & x )
66 {
67 std::cout << x.what() << std::endl;
68 }
69 }
70
71 static void scan_submodules( fs::path const & path )
72 {
73 fs::directory_iterator it( path ), last;
74
75 for( ; it != last; ++it )
76 {
77 fs::directory_entry const & e = *it;
78
79 if( e.status().type() != fs::directory_file )
80 {
81 continue;
82 }
83
84 fs::path path = e.path();
85
86 if( fs::exists( path / "include" ) )
87 {
88 scan_module_headers( path );
89 }
90
91 if( fs::exists( path / "sublibs" ) )
92 {
93 scan_submodules( path );
94 }
95 }
96 }
97
98 static void build_header_map()
99 {
100 scan_submodules( "libs" );
101 }
102
103 static void scan_header_dependencies( std::string const & header, std::istream & is, std::map< std::string, std::set< std::string > > & deps, std::map< std::string, std::set< std::string > > & from )
104 {
105 std::string line;
106
107 while( std::getline( is, line ) )
108 {
109 while( !line.empty() && ( line[0] == ' ' || line[0] == '\t' ) )
110 {
111 line.erase( 0, 1 );
112 }
113
114 if( line.empty() || line[0] != '#' ) continue;
115
116 line.erase( 0, 1 );
117
118 while( !line.empty() && ( line[0] == ' ' || line[0] == '\t' ) )
119 {
120 line.erase( 0, 1 );
121 }
122
123 if( line.substr( 0, 7 ) != "include" ) continue;
124
125 line.erase( 0, 7 );
126
127 while( !line.empty() && ( line[0] == ' ' || line[0] == '\t' ) )
128 {
129 line.erase( 0, 1 );
130 }
131
132 if( line.size() < 2 ) continue;
133
134 char ch = line[0];
135
136 if( ch != '<' && ch != '"' ) continue;
137
138 if( ch == '<' )
139 {
140 ch = '>';
141 }
142
143 line.erase( 0, 1 );
144
145 std::string::size_type k = line.find_first_of( ch );
146
147 if( k != std::string::npos )
148 {
149 line.erase( k );
150 }
151
152 std::map< std::string, std::string >::const_iterator i = s_header_map.find( line );
153
154 if( i != s_header_map.end() )
155 {
156 deps[ i->second ].insert( line );
157 from[ line ].insert( header );
158 }
159 else if( line.substr( 0, 6 ) == "boost/" )
160 {
161 deps[ "(unknown)" ].insert( line );
162 from[ line ].insert( header );
163 }
164 }
165 }
166
167 struct module_primary_actions
168 {
169 virtual void heading( std::string const & module ) = 0;
170
171 virtual void module_start( std::string const & module ) = 0;
172 virtual void module_end( std::string const & module ) = 0;
173
174 virtual void header_start( std::string const & header ) = 0;
175 virtual void header_end( std::string const & header ) = 0;
176
177 virtual void from_header( std::string const & header ) = 0;
178 };
179
180 static fs::path module_include_path( std::string module )
181 {
182 std::replace( module.begin(), module.end(), '~', '/' );
183 return fs::path( "libs" ) / module / "include";
184 }
185
186 static fs::path module_source_path( std::string module )
187 {
188 std::replace( module.begin(), module.end(), '~', '/' );
189 return fs::path( "libs" ) / module / "src";
190 }
191
192 static fs::path module_build_path( std::string module )
193 {
194 std::replace( module.begin(), module.end(), '~', '/' );
195 return fs::path( "libs" ) / module / "build";
196 }
197
198 static fs::path module_test_path( std::string module )
199 {
200 std::replace( module.begin(), module.end(), '~', '/' );
201 return fs::path( "libs" ) / module / "test";
202 }
203
204 static void scan_module_path( fs::path const & dir, bool remove_prefix, std::map< std::string, std::set< std::string > > & deps, std::map< std::string, std::set< std::string > > & from )
205 {
206 size_t n = dir.generic_string().size();
207
208 if( fs::exists( dir ) )
209 {
210 fs::recursive_directory_iterator it( dir ), last;
211
212 for( ; it != last; ++it )
213 {
214 if( it->status().type() == fs::directory_file )
215 {
216 continue;
217 }
218
219 std::string header = it->path().generic_string();
220
221 if( remove_prefix )
222 {
223 header = header.substr( n+1 );
224 }
225
226 fs::ifstream is( it->path() );
227
228 scan_header_dependencies( header, is, deps, from );
229 }
230 }
231 }
232
233 static void scan_module_dependencies( std::string const & module, module_primary_actions & actions, bool track_sources, bool track_tests, bool include_self )
234 {
235 // module -> [ header, header... ]
236 std::map< std::string, std::set< std::string > > deps;
237
238 // header -> included from [ header, header... ]
239 std::map< std::string, std::set< std::string > > from;
240
241 scan_module_path( module_include_path( module ), true, deps, from );
242
243 if( track_sources )
244 {
245 scan_module_path( module_source_path( module ), false, deps, from );
246 }
247
248 if( track_tests )
249 {
250 scan_module_path( module_test_path( module ), false, deps, from );
251 }
252
253 actions.heading( module );
254
255 for( std::map< std::string, std::set< std::string > >::iterator i = deps.begin(); i != deps.end(); ++i )
256 {
257 if( i->first == module && !include_self ) continue;
258
259 actions.module_start( i->first );
260
261 for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
262 {
263 actions.header_start( *j );
264
265 std::set< std::string > const & f = from[ *j ];
266
267 for( std::set< std::string >::const_iterator k = f.begin(); k != f.end(); ++k )
268 {
269 actions.from_header( *k );
270 }
271
272 actions.header_end( *j );
273 }
274
275 actions.module_end( i->first );
276 }
277 }
278
279 // module depends on [ module, module... ]
280 static std::map< std::string, std::set< std::string > > s_module_deps;
281
282 // header is included by [header, header...]
283 static std::map< std::string, std::set< std::string > > s_header_deps;
284
285 // [ module, module... ] depend on module
286 static std::map< std::string, std::set< std::string > > s_reverse_deps;
287
288 // header includes [header, header...]
289 static std::map< std::string, std::set< std::string > > s_header_includes;
290
291 struct build_mdmap_actions: public module_primary_actions
292 {
293 std::string module_;
294 std::string module2_;
295 std::string header_;
296
297 void heading( std::string const & module )
298 {
299 module_ = module;
300 }
301
302 void module_start( std::string const & module )
303 {
304 if( module != module_ )
305 {
306 s_module_deps[ module_ ].insert( module );
307 s_reverse_deps[ module ].insert( module_ );
308 }
309
310 module2_ = module;
311 }
312
313 void module_end( std::string const & /*module*/ )
314 {
315 }
316
317 void header_start( std::string const & header )
318 {
319 header_ = header;
320 }
321
322 void header_end( std::string const & /*header*/ )
323 {
324 }
325
326 void from_header( std::string const & header )
327 {
328 if( module_ != module2_ )
329 {
330 s_header_deps[ header_ ].insert( header );
331 }
332
333 s_header_includes[ header ].insert( header_ );
334 }
335 };
336
337 static void build_module_dependency_map( bool track_sources, bool track_tests )
338 {
339 for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
340 {
341 build_mdmap_actions actions;
342 scan_module_dependencies( *i, actions, track_sources, track_tests, true );
343 }
344 }
345
346 static void output_module_primary_report( std::string const & module, module_primary_actions & actions, bool track_sources, bool track_tests )
347 {
348 try
349 {
350 scan_module_dependencies( module, actions, track_sources, track_tests, false );
351 }
352 catch( fs::filesystem_error const & x )
353 {
354 std::cout << x.what() << std::endl;
355 }
356 }
357
358 struct module_secondary_actions
359 {
360 virtual void heading( std::string const & module ) = 0;
361
362 virtual void module_start( std::string const & module ) = 0;
363 virtual void module_end( std::string const & module ) = 0;
364
365 virtual void module_adds( std::string const & module ) = 0;
366 };
367
368 static void exclude( std::set< std::string > & x, std::set< std::string > const & y )
369 {
370 for( std::set< std::string >::const_iterator i = y.begin(); i != y.end(); ++i )
371 {
372 x.erase( *i );
373 }
374 }
375
376 static void output_module_secondary_report( std::string const & module, std::set< std::string> deps, module_secondary_actions & actions )
377 {
378 actions.heading( module );
379
380 deps.insert( module );
381
382 // build transitive closure
383
384 for( ;; )
385 {
386 std::set< std::string > deps2( deps );
387
388 for( std::set< std::string >::iterator i = deps.begin(); i != deps.end(); ++i )
389 {
390 std::set< std::string > deps3 = s_module_deps[ *i ];
391
392 exclude( deps3, deps );
393
394 if( deps3.empty() )
395 {
396 continue;
397 }
398
399 actions.module_start( *i );
400
401 for( std::set< std::string >::iterator j = deps3.begin(); j != deps3.end(); ++j )
402 {
403 actions.module_adds( *j );
404 }
405
406 actions.module_end( *i );
407
408 deps2.insert( deps3.begin(), deps3.end() );
409 }
410
411 if( deps == deps2 )
412 {
413 break;
414 }
415 else
416 {
417 deps = deps2;
418 }
419 }
420 }
421
422 static void output_module_secondary_report( std::string const & module, module_secondary_actions & actions )
423 {
424 output_module_secondary_report( module, s_module_deps[ module ], actions );
425 }
426
427 struct header_inclusion_actions
428 {
429 virtual void heading( std::string const & header, std::string const & module ) = 0;
430
431 virtual void module_start( std::string const & module ) = 0;
432 virtual void module_end( std::string const & module ) = 0;
433
434 virtual void header( std::string const & header ) = 0;
435 };
436
437 static void output_header_inclusion_report( std::string const & header, header_inclusion_actions & actions )
438 {
439 std::string module = s_header_map[ header ];
440
441 actions.heading( header, module );
442
443 std::set< std::string > from = s_header_deps[ header ];
444
445 // classify 'from' dependencies by module
446
447 // module -> [header, header...]
448 std::map< std::string, std::set< std::string > > from2;
449
450 for( std::set< std::string >::iterator i = from.begin(); i != from.end(); ++i )
451 {
452 from2[ s_header_map[ *i ] ].insert( *i );
453 }
454
455 for( std::map< std::string, std::set< std::string > >::iterator i = from2.begin(); i != from2.end(); ++i )
456 {
457 actions.module_start( i->first );
458
459 for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
460 {
461 actions.header( *j );
462 }
463
464 actions.module_end( i->first );
465 }
466 }
467
468 // output_module_primary_report
469
470 struct module_primary_txt_actions: public module_primary_actions
471 {
472 void heading( std::string const & module )
473 {
474 std::cout << "Primary dependencies for " << module << ":\n\n";
475 }
476
477 void module_start( std::string const & module )
478 {
479 std::cout << module << ":\n";
480 }
481
482 void module_end( std::string const & /*module*/ )
483 {
484 std::cout << "\n";
485 }
486
487 void header_start( std::string const & header )
488 {
489 std::cout << " <" << header << ">\n";
490 }
491
492 void header_end( std::string const & /*header*/ )
493 {
494 }
495
496 void from_header( std::string const & header )
497 {
498 std::cout << " from <" << header << ">\n";
499 }
500 };
501
502 struct module_primary_html_actions: public module_primary_actions
503 {
504 void heading( std::string const & module )
505 {
506 std::cout << "\n\n<h1 id=\"primary-dependencies\">Primary dependencies for <em>" << module << "</em></h1>\n";
507 }
508
509 void module_start( std::string const & module )
510 {
511 std::cout << " <h2 id=\"" << module << "\"><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2>\n";
512 }
513
514 void module_end( std::string const & /*module*/ )
515 {
516 }
517
518 void header_start( std::string const & header )
519 {
520 std::cout << " <h3><code>&lt;" << header << "&gt;</code></h3><ul>\n";
521 }
522
523 void header_end( std::string const & /*header*/ )
524 {
525 std::cout << " </ul>\n";
526 }
527
528 void from_header( std::string const & header )
529 {
530 std::cout << " <li>from <code>&lt;" << header << "&gt;</code></li>\n";
531 }
532 };
533
534 static void output_module_primary_report( std::string const & module, bool html, bool track_sources, bool track_tests )
535 {
536 if( html )
537 {
538 module_primary_html_actions actions;
539 output_module_primary_report( module, actions, track_sources, track_tests );
540 }
541 else
542 {
543 module_primary_txt_actions actions;
544 output_module_primary_report( module, actions, track_sources, track_tests );
545 }
546 }
547
548 // output_module_secondary_report
549
550 struct module_secondary_txt_actions: public module_secondary_actions
551 {
552 void heading( std::string const & module )
553 {
554 std::cout << "Secondary dependencies for " << module << ":\n\n";
555 }
556
557 void module_start( std::string const & module )
558 {
559 std::cout << module << ":\n";
560 }
561
562 void module_end( std::string const & /*module*/ )
563 {
564 std::cout << "\n";
565 }
566
567 void module_adds( std::string const & module )
568 {
569 std::cout << " adds " << module << "\n";
570 }
571 };
572
573 struct module_secondary_html_actions: public module_secondary_actions
574 {
575 std::string m2_;
576
577 void heading( std::string const & module )
578 {
579 std::cout << "\n\n<h1 id=\"secondary-dependencies\">Secondary dependencies for <em>" << module << "</em></h1>\n";
580 }
581
582 void module_start( std::string const & module )
583 {
584 std::cout << " <h2><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2><ul>\n";
585 m2_ = module;
586 }
587
588 void module_end( std::string const & /*module*/ )
589 {
590 std::cout << " </ul>\n";
591 }
592
593 void module_adds( std::string const & module )
594 {
595 std::cout << " <li><a href=\"" << m2_ << ".html#" << module << "\">adds <em>" << module << "</em></a></li>\n";
596 }
597 };
598
599 static void output_module_secondary_report( std::string const & module, bool html )
600 {
601 if( html )
602 {
603 module_secondary_html_actions actions;
604 output_module_secondary_report( module, actions );
605 }
606 else
607 {
608 module_secondary_txt_actions actions;
609 output_module_secondary_report( module, actions );
610 }
611 }
612
613 // output_header_report
614
615 struct header_inclusion_txt_actions: public header_inclusion_actions
616 {
617 void heading( std::string const & header, std::string const & module )
618 {
619 std::cout << "Inclusion report for <" << header << "> (in module " << module << "):\n\n";
620 }
621
622 void module_start( std::string const & module )
623 {
624 std::cout << " from " << module << ":\n";
625 }
626
627 void module_end( std::string const & /*module*/ )
628 {
629 std::cout << "\n";
630 }
631
632 void header( std::string const & header )
633 {
634 std::cout << " <" << header << ">\n";
635 }
636 };
637
638 struct header_inclusion_html_actions: public header_inclusion_actions
639 {
640 void heading( std::string const & header, std::string const & module )
641 {
642 std::cout << "<h1>Inclusion report for <code>&lt;" << header << "&gt;</code> (in module <em>" << module << "</em>)</h1>\n";
643 }
644
645 void module_start( std::string const & module )
646 {
647 std::cout << " <h2>From <a href=\"" << module << ".html\"><em>" << module << "</em></a></h2><ul>\n";
648 }
649
650 void module_end( std::string const & /*module*/ )
651 {
652 std::cout << " </ul>\n";
653 }
654
655 void header( std::string const & header )
656 {
657 std::cout << " <li><code>&lt;" << header << "&gt;</code></li>\n";
658 }
659 };
660
661 static void output_header_report( std::string const & header, bool html )
662 {
663 if( html )
664 {
665 header_inclusion_html_actions actions;
666 output_header_inclusion_report( header, actions );
667 }
668 else
669 {
670 header_inclusion_txt_actions actions;
671 output_header_inclusion_report( header, actions );
672 }
673 }
674
675 // output_module_reverse_report
676
677 struct module_reverse_actions
678 {
679 virtual void heading( std::string const & module ) = 0;
680
681 virtual void module_start( std::string const & module ) = 0;
682 virtual void module_end( std::string const & module ) = 0;
683
684 virtual void header_start( std::string const & header ) = 0;
685 virtual void header_end( std::string const & header ) = 0;
686
687 virtual void from_header( std::string const & header ) = 0;
688 };
689
690 static void output_module_reverse_report( std::string const & module, module_reverse_actions & actions )
691 {
692 actions.heading( module );
693
694 std::set< std::string > const from = s_reverse_deps[ module ];
695
696 for( std::set< std::string >::const_iterator i = from.begin(); i != from.end(); ++i )
697 {
698 actions.module_start( *i );
699
700 for( std::map< std::string, std::set< std::string > >::iterator j = s_header_deps.begin(); j != s_header_deps.end(); ++j )
701 {
702 if( s_header_map[ j->first ] == module )
703 {
704 bool header_started = false;
705
706 for( std::set< std::string >::iterator k = j->second.begin(); k != j->second.end(); ++k )
707 {
708 if( s_header_map[ *k ] == *i )
709 {
710 if( !header_started )
711 {
712 actions.header_start( j->first );
713
714 header_started = true;
715 }
716
717 actions.from_header( *k );
718 }
719 }
720
721 if( header_started )
722 {
723 actions.header_end( j->first );
724 }
725 }
726 }
727
728 actions.module_end( *i );
729 }
730 }
731
732 struct module_reverse_txt_actions: public module_reverse_actions
733 {
734 void heading( std::string const & module )
735 {
736 std::cout << "Reverse dependencies for " << module << ":\n\n";
737 }
738
739 void module_start( std::string const & module )
740 {
741 std::cout << module << ":\n";
742 }
743
744 void module_end( std::string const & /*module*/ )
745 {
746 std::cout << "\n";
747 }
748
749 void header_start( std::string const & header )
750 {
751 std::cout << " <" << header << ">\n";
752 }
753
754 void header_end( std::string const & /*header*/ )
755 {
756 }
757
758 void from_header( std::string const & header )
759 {
760 std::cout << " from <" << header << ">\n";
761 }
762 };
763
764 struct module_reverse_html_actions: public module_reverse_actions
765 {
766 void heading( std::string const & module )
767 {
768 std::cout << "\n\n<h1 id=\"reverse-dependencies\">Reverse dependencies for <em>" << module << "</em></h1>\n";
769 }
770
771 void module_start( std::string const & module )
772 {
773 std::cout << " <h2 id=\"reverse-" << module << "\"><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2>\n";
774 }
775
776 void module_end( std::string const & /*module*/ )
777 {
778 }
779
780 void header_start( std::string const & header )
781 {
782 std::cout << " <h3><code>&lt;" << header << "&gt;</code></h3><ul>\n";
783 }
784
785 void header_end( std::string const & /*header*/ )
786 {
787 std::cout << " </ul>\n";
788 }
789
790 void from_header( std::string const & header )
791 {
792 std::cout << " <li>from <code>&lt;" << header << "&gt;</code></li>\n";
793 }
794 };
795
796 static void output_module_reverse_report( std::string const & module, bool html )
797 {
798 if( html )
799 {
800 module_reverse_html_actions actions;
801 output_module_reverse_report( module, actions );
802 }
803 else
804 {
805 module_reverse_txt_actions actions;
806 output_module_reverse_report( module, actions );
807 }
808 }
809
810 // module_level_report
811
812 int const unknown_level = INT_MAX / 2;
813
814 struct module_level_actions
815 {
816 virtual void begin() = 0;
817 virtual void end() = 0;
818
819 virtual void level_start( int level ) = 0;
820 virtual void level_end( int level ) = 0;
821
822 virtual void module_start( std::string const & module ) = 0;
823 virtual void module_end( std::string const & module ) = 0;
824
825 virtual void module2( std::string const & module, int level ) = 0;
826 };
827
828 static void output_module_level_report( module_level_actions & actions )
829 {
830 // build module level map
831
832 std::map< std::string, int > level_map;
833
834 for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
835 {
836 if( s_module_deps[ *i ].empty() )
837 {
838 level_map[ *i ] = 0;
839 // std::cerr << *i << ": " << 0 << std::endl;
840 }
841 else
842 {
843 level_map[ *i ] = unknown_level;
844 }
845 }
846
847 // build transitive closure to see through cycles
848
849 std::map< std::string, std::set< std::string > > deps2 = s_module_deps;
850
851 {
852 bool done;
853
854 do
855 {
856 done = true;
857
858 for( std::map< std::string, std::set< std::string > >::iterator i = deps2.begin(); i != deps2.end(); ++i )
859 {
860 std::set< std::string > tmp = i->second;
861
862 for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
863 {
864 std::set< std::string > tmp2 = deps2[ *j ];
865 tmp.insert( tmp2.begin(), tmp2.end() );
866 }
867
868 if( tmp.size() != i->second.size() )
869 {
870 i->second = tmp;
871 done = false;
872 }
873 }
874 }
875 while( !done );
876 }
877
878 // compute acyclic levels
879
880 for( int k = 1, n = s_modules.size(); k < n; ++k )
881 {
882 for( std::map< std::string, std::set< std::string > >::iterator i = s_module_deps.begin(); i != s_module_deps.end(); ++i )
883 {
884 // i->first depends on i->second
885
886 if( level_map[ i->first ] >= unknown_level )
887 {
888 int level = 0;
889
890 for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
891 {
892 level = std::max( level, level_map[ *j ] + 1 );
893 }
894
895 if( level == k )
896 {
897 level_map[ i->first ] = level;
898 // std::cerr << i->first << ": " << level << std::endl;
899 }
900 }
901 }
902 }
903
904 // min_level_map[ M ] == L means the level is unknown, but at least L
905 std::map< std::string, int > min_level_map;
906
907 // initialize min_level_map for acyclic dependencies
908
909 for( std::map< std::string, int >::iterator i = level_map.begin(); i != level_map.end(); ++i )
910 {
911 if( i->second < unknown_level )
912 {
913 min_level_map[ i->first ] = i->second;
914 }
915 }
916
917 // compute levels for cyclic modules
918
919 for( int k = 1, n = s_modules.size(); k < n; ++k )
920 {
921 for( std::map< std::string, std::set< std::string > >::iterator i = s_module_deps.begin(); i != s_module_deps.end(); ++i )
922 {
923 if( level_map[ i->first ] >= unknown_level )
924 {
925 int level = 0;
926
927 for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
928 {
929 int jl = level_map[ *j ];
930
931 if( jl < unknown_level )
932 {
933 level = std::max( level, jl + 1 );
934 }
935 else
936 {
937 int ml = min_level_map[ *j ];
938
939 if( deps2[ *j ].count( i->first ) == 0 )
940 {
941 // *j does not depend on i->first, so
942 // the level of i->first is at least
943 // 1 + the minimum level of *j
944
945 ++ml;
946 }
947
948 level = std::max( level, ml );
949 }
950 }
951
952 min_level_map[ i->first ] = level;
953 }
954 }
955 }
956
957 // reverse level map
958
959 std::map< int, std::set< std::string > > reverse_level_map;
960
961 for( std::map< std::string, int >::iterator i = level_map.begin(); i != level_map.end(); ++i )
962 {
963 int level = i->second;
964
965 if( level >= unknown_level )
966 {
967 int min_level = min_level_map[ i->first ];
968
969 if( min_level != 0 )
970 {
971 level = min_level;
972 }
973 }
974
975 reverse_level_map[ level ].insert( i->first );
976 }
977
978 // output report
979
980 actions.begin();
981
982 for( std::map< int, std::set< std::string > >::iterator i = reverse_level_map.begin(); i != reverse_level_map.end(); ++i )
983 {
984 actions.level_start( i->first );
985
986 for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
987 {
988 actions.module_start( *j );
989
990 std::set< std::string > mdeps = s_module_deps[ *j ];
991
992 for( std::set< std::string >::iterator k = mdeps.begin(); k != mdeps.end(); ++k )
993 {
994 int level = level_map[ *k ];
995
996 if( level >= unknown_level )
997 {
998 int min_level = min_level_map[ *k ];
999
1000 if( min_level != 0 )
1001 {
1002 level = min_level;
1003 }
1004 }
1005
1006 actions.module2( *k, level );
1007 }
1008
1009 actions.module_end( *j );
1010 }
1011
1012 actions.level_end( i->first );
1013 }
1014
1015 actions.end();
1016 }
1017
1018 struct module_level_txt_actions: public module_level_actions
1019 {
1020 int level_;
1021
1022 void begin()
1023 {
1024 std::cout << "Module Levels:\n\n";
1025 }
1026
1027 void end()
1028 {
1029 }
1030
1031 void level_start( int level )
1032 {
1033 if( level >= unknown_level )
1034 {
1035 std::cout << "Level (undetermined):\n";
1036 }
1037 else
1038 {
1039 std::cout << "Level " << level << ":\n";
1040 }
1041
1042 level_ = level;
1043 }
1044
1045 void level_end( int /*level*/ )
1046 {
1047 std::cout << "\n";
1048 }
1049
1050 void module_start( std::string const & module )
1051 {
1052 std::cout << " " << module;
1053
1054 if( level_ > 0 )
1055 {
1056 std::cout << " ->";
1057 }
1058 }
1059
1060 void module_end( std::string const & /*module*/ )
1061 {
1062 std::cout << "\n";
1063 }
1064
1065 void module2( std::string const & module, int level )
1066 {
1067 std::cout << " " << module << "(";
1068
1069 if( level >= unknown_level )
1070 {
1071 std::cout << "-";
1072 }
1073 else
1074 {
1075 std::cout << level;
1076 }
1077
1078 std::cout << ")";
1079 }
1080 };
1081
1082 struct module_level_html_actions: public module_level_actions
1083 {
1084 int level_;
1085
1086 void begin()
1087 {
1088 std::cout << "<div id='module-levels'><h1>Module Levels</h1>\n";
1089 }
1090
1091 void end()
1092 {
1093 std::cout << "</div>\n";
1094 }
1095
1096 void level_start( int level )
1097 {
1098 if( level >= unknown_level )
1099 {
1100 std::cout << " <h2>Level <em>undetermined</em></h2>\n";
1101 }
1102 else
1103 {
1104 std::cout << " <h2 id='level:" << level << "'>Level " << level << "</h2>\n";
1105 }
1106
1107 level_ = level;
1108 }
1109
1110 void level_end( int /*level*/ )
1111 {
1112 }
1113
1114 void module_start( std::string const & module )
1115 {
1116 std::cout << " <h3 id='" << module << "'><a href=\"" << module << ".html\">" << module << "</a></h3><p class='primary-list'>";
1117 }
1118
1119 void module_end( std::string const & /*module*/ )
1120 {
1121 std::cout << "</p>\n";
1122 }
1123
1124 void module2( std::string const & module, int level )
1125 {
1126 std::cout << " ";
1127
1128 bool important = level < unknown_level && level > 1 && level >= level_ - 1;
1129
1130 if( important )
1131 {
1132 std::cout << "<strong>";
1133 }
1134
1135 std::cout << module;
1136
1137 if( level < unknown_level )
1138 {
1139 std::cout << "<sup>" << level << "</sup>";
1140 }
1141
1142 if( important )
1143 {
1144 std::cout << "</strong>";
1145 }
1146 }
1147 };
1148
1149 static void output_module_level_report( bool html )
1150 {
1151 if( html )
1152 {
1153 module_level_html_actions actions;
1154 output_module_level_report( actions );
1155 }
1156 else
1157 {
1158 module_level_txt_actions actions;
1159 output_module_level_report( actions );
1160 }
1161 }
1162
1163 // module_overview_report
1164
1165 struct module_overview_actions
1166 {
1167 virtual void begin() = 0;
1168 virtual void end() = 0;
1169
1170 virtual void module_start( std::string const & module ) = 0;
1171 virtual void module_end( std::string const & module ) = 0;
1172
1173 virtual void module2( std::string const & module ) = 0;
1174 };
1175
1176 static void output_module_overview_report( module_overview_actions & actions )
1177 {
1178 actions.begin();
1179
1180 for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
1181 {
1182 actions.module_start( *i );
1183
1184 std::set< std::string > const mdeps = s_module_deps[ *i ];
1185
1186 for( std::set< std::string >::const_iterator j = mdeps.begin(); j != mdeps.end(); ++j )
1187 {
1188 actions.module2( *j );
1189 }
1190
1191 actions.module_end( *i );
1192 }
1193
1194 actions.end();
1195 }
1196
1197 struct module_overview_txt_actions: public module_overview_actions
1198 {
1199 bool deps_;
1200
1201 void begin()
1202 {
1203 std::cout << "Module Overview:\n\n";
1204 }
1205
1206 void end()
1207 {
1208 }
1209
1210 void module_start( std::string const & module )
1211 {
1212 std::cout << module;
1213 deps_ = false;
1214 }
1215
1216 void module_end( std::string const & /*module*/ )
1217 {
1218 std::cout << "\n";
1219 }
1220
1221 void module2( std::string const & module )
1222 {
1223 if( !deps_ )
1224 {
1225 std::cout << " ->";
1226 deps_ = true;
1227 }
1228
1229 std::cout << " " << module;
1230 }
1231 };
1232
1233 struct module_overview_html_actions: public module_overview_actions
1234 {
1235 void begin()
1236 {
1237 std::cout << "<div id='module-overview'><h1>Module Overview</h1>\n";
1238 }
1239
1240 void end()
1241 {
1242 std::cout << "</div>\n";
1243 }
1244
1245 void module_start( std::string const & module )
1246 {
1247 std::cout << " <h2 id='" << module << "'><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2><p class='primary-list'>";
1248 }
1249
1250 void module_end( std::string const & /*module*/ )
1251 {
1252 std::cout << "</p>\n";
1253 }
1254
1255 void module2( std::string const & module )
1256 {
1257 std::cout << " " << module;
1258 }
1259 };
1260
1261 static void output_module_overview_report( bool html )
1262 {
1263 if( html )
1264 {
1265 module_overview_html_actions actions;
1266 output_module_overview_report( actions );
1267 }
1268 else
1269 {
1270 module_overview_txt_actions actions;
1271 output_module_overview_report( actions );
1272 }
1273 }
1274
1275 // list_dependencies
1276
1277 struct list_dependencies_actions: public module_overview_actions
1278 {
1279 void begin()
1280 {
1281 }
1282
1283 void end()
1284 {
1285 }
1286
1287 void module_start( std::string const & module )
1288 {
1289 std::cout << module << " ->";
1290 }
1291
1292 void module_end( std::string const & /*module*/ )
1293 {
1294 std::cout << "\n";
1295 }
1296
1297 void module2( std::string const & module )
1298 {
1299 if( module != "(unknown)" )
1300 {
1301 std::cout << " " << module;
1302 }
1303 }
1304 };
1305
1306 static void list_dependencies()
1307 {
1308 list_dependencies_actions actions;
1309 output_module_overview_report( actions );
1310 }
1311
1312 //
1313
1314 static void output_html_header( std::string const & title, std::string const & stylesheet, std::string const & prefix )
1315 {
1316 std::cout << "<html>\n";
1317 std::cout << "<head>\n";
1318 std::cout << "<title>" << title << "</title>\n";
1319
1320 if( !stylesheet.empty() )
1321 {
1322 std::cout << "<link rel=\"stylesheet\" type=\"text/css\" href=\"" << stylesheet << "\" />\n";
1323 }
1324
1325 std::cout << "</head>\n";
1326 std::cout << "<body>\n";
1327
1328 if( !prefix.empty() )
1329 {
1330 std::cout << prefix << std::endl;
1331 }
1332 }
1333
1334 static void output_html_footer( std::string const & footer )
1335 {
1336 std::cout << "<hr />\n";
1337 std::cout << "<p class=\"footer\">" << footer << "</p>\n";
1338 std::cout << "</body>\n";
1339 std::cout << "</html>\n";
1340 }
1341
1342 static void enable_secondary( bool & secondary, bool track_sources, bool track_tests )
1343 {
1344 if( !secondary )
1345 {
1346 try
1347 {
1348 build_module_dependency_map( track_sources, track_tests );
1349 }
1350 catch( fs::filesystem_error const & x )
1351 {
1352 std::cout << x.what() << std::endl;
1353 }
1354
1355 secondary = true;
1356 }
1357 }
1358
1359 static void list_modules()
1360 {
1361 for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
1362 {
1363 std::cout << *i << "\n";
1364 }
1365 }
1366
1367 static void list_buildable()
1368 {
1369 for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
1370 {
1371 if( fs::exists( module_build_path( *i ) ) && fs::exists( module_source_path( *i ) ) )
1372 {
1373 std::cout << *i << "\n";
1374 }
1375 }
1376 }
1377
1378 // module_weight_report
1379
1380 struct module_weight_actions
1381 {
1382 virtual void begin() = 0;
1383 virtual void end() = 0;
1384
1385 virtual void weight_start( int weight ) = 0;
1386 virtual void weight_end( int weight ) = 0;
1387
1388 virtual void module_start( std::string const & module ) = 0;
1389 virtual void module_end( std::string const & module ) = 0;
1390
1391 virtual void module_primary_start() = 0;
1392 virtual void module_primary( std::string const & module, int weight ) = 0;
1393 virtual void module_primary_end() = 0;
1394
1395 virtual void module_secondary_start() = 0;
1396 virtual void module_secondary( std::string const & module, int weight ) = 0;
1397 virtual void module_secondary_end() = 0;
1398 };
1399
1400 static void output_module_weight_report( module_weight_actions & actions )
1401 {
1402 // gather secondary dependencies
1403
1404 struct build_secondary_deps: public module_secondary_actions
1405 {
1406 std::map< std::string, std::set< std::string > > * pm_;
1407
1408 build_secondary_deps( std::map< std::string, std::set< std::string > > * pm ): pm_( pm )
1409 {
1410 }
1411
1412 std::string module_;
1413
1414 void heading( std::string const & module )
1415 {
1416 module_ = module;
1417 }
1418
1419 void module_start( std::string const & /*module*/ )
1420 {
1421 }
1422
1423 void module_end( std::string const & /*module*/ )
1424 {
1425 }
1426
1427 void module_adds( std::string const & module )
1428 {
1429 (*pm_)[ module_ ].insert( module );
1430 }
1431 };
1432
1433 std::map< std::string, std::set< std::string > > secondary_deps;
1434
1435 build_secondary_deps bsd( &secondary_deps );
1436
1437 for( std::set< std::string >::const_iterator i = s_modules.begin(); i != s_modules.end(); ++i )
1438 {
1439 output_module_secondary_report( *i, bsd );
1440 }
1441
1442 // build weight map
1443
1444 std::map< int, std::set< std::string > > modules_by_weight;
1445
1446 for( std::set< std::string >::const_iterator i = s_modules.begin(); i != s_modules.end(); ++i )
1447 {
1448 int w = s_module_deps[ *i ].size() + secondary_deps[ *i ].size();
1449 modules_by_weight[ w ].insert( *i );
1450 }
1451
1452 // output report
1453
1454 actions.begin();
1455
1456 for( std::map< int, std::set< std::string > >::const_iterator i = modules_by_weight.begin(); i != modules_by_weight.end(); ++i )
1457 {
1458 actions.weight_start( i->first );
1459
1460 for( std::set< std::string >::const_iterator j = i->second.begin(); j != i->second.end(); ++j )
1461 {
1462 actions.module_start( *j );
1463
1464 if( !s_module_deps[ *j ].empty() )
1465 {
1466 actions.module_primary_start();
1467
1468 for( std::set< std::string >::const_iterator k = s_module_deps[ *j ].begin(); k != s_module_deps[ *j ].end(); ++k )
1469 {
1470 int w = s_module_deps[ *k ].size() + secondary_deps[ *k ].size();
1471 actions.module_primary( *k, w );
1472 }
1473
1474 actions.module_primary_end();
1475 }
1476
1477 if( !secondary_deps[ *j ].empty() )
1478 {
1479 actions.module_secondary_start();
1480
1481 for( std::set< std::string >::const_iterator k = secondary_deps[ *j ].begin(); k != secondary_deps[ *j ].end(); ++k )
1482 {
1483 int w = s_module_deps[ *k ].size() + secondary_deps[ *k ].size();
1484 actions.module_secondary( *k, w );
1485 }
1486
1487 actions.module_secondary_end();
1488 }
1489
1490 actions.module_end( *j );
1491 }
1492
1493 actions.weight_end( i->first );
1494 }
1495
1496 actions.end();
1497 }
1498
1499 struct module_weight_txt_actions: public module_weight_actions
1500 {
1501 void begin()
1502 {
1503 std::cout << "Module Weights:\n\n";
1504 }
1505
1506 void end()
1507 {
1508 }
1509
1510 void weight_start( int weight )
1511 {
1512 std::cout << "Weight " << weight << ":\n";
1513 }
1514
1515 void weight_end( int /*weight*/ )
1516 {
1517 std::cout << "\n";
1518 }
1519
1520 void module_start( std::string const & module )
1521 {
1522 std::cout << " " << module;
1523 }
1524
1525 void module_end( std::string const & /*module*/ )
1526 {
1527 std::cout << "\n";
1528 }
1529
1530 void module_primary_start()
1531 {
1532 std::cout << " ->";
1533 }
1534
1535 void module_primary( std::string const & module, int weight )
1536 {
1537 std::cout << " " << module << "(" << weight << ")";
1538 }
1539
1540 void module_primary_end()
1541 {
1542 }
1543
1544 void module_secondary_start()
1545 {
1546 std::cout << " ->";
1547 }
1548
1549 void module_secondary( std::string const & module, int /*weight*/ )
1550 {
1551 std::cout << " " << module;
1552 }
1553
1554 void module_secondary_end()
1555 {
1556 }
1557 };
1558
1559 struct module_weight_html_actions: public module_weight_actions
1560 {
1561 int weight_;
1562
1563 void begin()
1564 {
1565 std::cout << "<div id='module-weights'>\n<h1>Module Weights</h1>\n";
1566 }
1567
1568 void end()
1569 {
1570 std::cout << "</div>\n";
1571 }
1572
1573 void weight_start( int weight )
1574 {
1575 std::cout << " <h2 id='weight:" << weight << "'>Weight " << weight << "</h2>\n";
1576 weight_ = weight;
1577 }
1578
1579 void weight_end( int /*weight*/ )
1580 {
1581 }
1582
1583 void module_start( std::string const & module )
1584 {
1585 std::cout << " <h3 id='" << module << "'><a href=\"" << module << ".html\">" << module << "</a></h3>";
1586 }
1587
1588 void module_end( std::string const & /*module*/ )
1589 {
1590 std::cout << "\n";
1591 }
1592
1593 void module_primary_start()
1594 {
1595 std::cout << "<p class='primary-list'>";
1596 }
1597
1598 void module_primary( std::string const & module, int weight )
1599 {
1600 std::cout << " ";
1601
1602 bool heavy = weight >= 0.8 * weight_;
1603
1604 if( heavy )
1605 {
1606 std::cout << "<strong>";
1607 }
1608
1609 std::cout << module << "<sup>" << weight << "</sup>";
1610
1611 if( heavy )
1612 {
1613 std::cout << "</strong>";
1614 }
1615 }
1616
1617 void module_primary_end()
1618 {
1619 std::cout << "</p>";
1620 }
1621
1622 void module_secondary_start()
1623 {
1624 std::cout << "<p class='secondary-list'>";
1625 }
1626
1627 void module_secondary( std::string const & module, int /*weight*/ )
1628 {
1629 std::cout << " " << module;
1630 }
1631
1632 void module_secondary_end()
1633 {
1634 std::cout << "</p>";
1635 }
1636 };
1637
1638 static void output_module_weight_report( bool html )
1639 {
1640 if( html )
1641 {
1642 module_weight_html_actions actions;
1643 output_module_weight_report( actions );
1644 }
1645 else
1646 {
1647 module_weight_txt_actions actions;
1648 output_module_weight_report( actions );
1649 }
1650 }
1651
1652 // output_module_subset_report
1653
1654 struct module_subset_actions
1655 {
1656 virtual void heading( std::string const & module ) = 0;
1657
1658 virtual void module_start( std::string const & module ) = 0;
1659 virtual void module_end( std::string const & module ) = 0;
1660
1661 virtual void from_path( std::vector<std::string> const & path ) = 0;
1662 };
1663
1664 static void add_module_headers( fs::path const & dir, std::set<std::string> & headers )
1665 {
1666 if( fs::exists( dir ) )
1667 {
1668 fs::recursive_directory_iterator it( dir ), last;
1669
1670 for( ; it != last; ++it )
1671 {
1672 if( it->status().type() == fs::directory_file )
1673 {
1674 continue;
1675 }
1676
1677 headers.insert( it->path().generic_string() );
1678 }
1679 }
1680 }
1681
1682 static void output_module_subset_report_( std::string const & module, std::set<std::string> const & headers, module_subset_actions & actions )
1683 {
1684 // build header closure
1685
1686 // header -> (header)*
1687 std::map< std::string, std::set<std::string> > inc2;
1688
1689 // (header, header) -> path
1690 std::map< std::pair<std::string, std::string>, std::vector<std::string> > paths;
1691
1692 for( std::set<std::string>::const_iterator i = headers.begin(); i != headers.end(); ++i )
1693 {
1694 std::set<std::string> & s = inc2[ *i ];
1695
1696 s = s_header_includes[ *i ];
1697
1698 for( std::set<std::string>::const_iterator j = s.begin(); j != s.end(); ++j )
1699 {
1700 std::vector<std::string> & v = paths[ std::make_pair( *i, *j ) ];
1701
1702 v.resize( 0 );
1703 v.push_back( *i );
1704 v.push_back( *j );
1705 }
1706 }
1707
1708 for( ;; )
1709 {
1710 bool r = false;
1711
1712 for( std::map< std::string, std::set<std::string> >::iterator i = inc2.begin(); i != inc2.end(); ++i )
1713 {
1714 std::set<std::string> & s2 = i->second;
1715
1716 for( std::set<std::string>::const_iterator j = s2.begin(); j != s2.end(); ++j )
1717 {
1718 std::set<std::string> const & s = s_header_includes[ *j ];
1719
1720 for( std::set<std::string>::const_iterator k = s.begin(); k != s.end(); ++k )
1721 {
1722 if( s2.count( *k ) == 0 )
1723 {
1724 s2.insert( *k );
1725
1726 std::vector<std::string> const & v1 = paths[ std::make_pair( i->first, *j ) ];
1727 std::vector<std::string> & v2 = paths[ std::make_pair( i->first, *k ) ];
1728
1729 v2 = v1;
1730 v2.push_back( *k );
1731
1732 r = true;
1733 }
1734 }
1735 }
1736 }
1737
1738 if( !r ) break;
1739 }
1740
1741 // module -> header -> path [header -> header -> header]
1742 std::map< std::string, std::map< std::string, std::vector<std::string> > > subset;
1743
1744 for( std::set<std::string>::const_iterator i = headers.begin(); i != headers.end(); ++i )
1745 {
1746 std::set<std::string> const & s = inc2[ *i ];
1747
1748 for( std::set<std::string>::const_iterator j = s.begin(); j != s.end(); ++j )
1749 {
1750 std::string const & m = s_header_map[ *j ];
1751
1752 if( m.empty() ) continue;
1753
1754 std::vector<std::string> const & path = paths[ std::make_pair( *i, *j ) ];
1755
1756 if( subset.count( m ) == 0 || subset[ m ].count( *i ) == 0 || subset[ m ][ *i ].size() > path.size() )
1757 {
1758 subset[ m ][ *i ] = path;
1759 }
1760 }
1761 }
1762
1763 actions.heading( module );
1764
1765 for( std::map< std::string, std::map< std::string, std::vector<std::string> > >::const_iterator i = subset.begin(); i != subset.end(); ++i )
1766 {
1767 if( i->first == module ) continue;
1768
1769 actions.module_start( i->first );
1770
1771 int k = 0;
1772
1773 for( std::map< std::string, std::vector<std::string> >::const_iterator j = i->second.begin(); j != i->second.end() && k < 4; ++j, ++k )
1774 {
1775 actions.from_path( j->second );
1776 }
1777
1778 actions.module_end( i->first );
1779 }
1780 }
1781
1782 static void output_module_subset_report( std::string const & module, bool track_sources, bool track_tests, module_subset_actions & actions )
1783 {
1784 std::set<std::string> headers = s_module_headers[ module ];
1785
1786 if( track_sources )
1787 {
1788 add_module_headers( module_source_path( module ), headers );
1789 }
1790
1791 if( track_tests )
1792 {
1793 add_module_headers( module_test_path( module ), headers );
1794 }
1795
1796 output_module_subset_report_( module, headers, actions );
1797 }
1798
1799 struct module_subset_txt_actions: public module_subset_actions
1800 {
1801 void heading( std::string const & module )
1802 {
1803 std::cout << "Subset dependencies for " << module << ":\n\n";
1804 }
1805
1806 void module_start( std::string const & module )
1807 {
1808 std::cout << module << ":\n";
1809 }
1810
1811 void module_end( std::string const & /*module*/ )
1812 {
1813 std::cout << "\n";
1814 }
1815
1816 void from_path( std::vector<std::string> const & path )
1817 {
1818 for( std::vector<std::string>::const_iterator i = path.begin(); i != path.end(); ++i )
1819 {
1820 if( i == path.begin() )
1821 {
1822 std::cout << " ";
1823 }
1824 else
1825 {
1826 std::cout << " -> ";
1827 }
1828
1829 std::cout << *i;
1830 }
1831
1832 std::cout << "\n";
1833 }
1834 };
1835
1836 struct module_subset_html_actions: public module_subset_actions
1837 {
1838 void heading( std::string const & module )
1839 {
1840 std::cout << "\n\n<h1 id=\"subset-dependencies\">Subset dependencies for <em>" << module << "</em></h1>\n";
1841 }
1842
1843 void module_start( std::string const & module )
1844 {
1845 std::cout << " <h2 id=\"subset-" << module << "\"><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2><ul>\n";
1846 }
1847
1848 void module_end( std::string const & /*module*/ )
1849 {
1850 std::cout << "</ul>\n";
1851 }
1852
1853 void from_path( std::vector<std::string> const & path )
1854 {
1855 std::cout << " <li>";
1856
1857 for( std::vector<std::string>::const_iterator i = path.begin(); i != path.end(); ++i )
1858 {
1859 if( i != path.begin() )
1860 {
1861 std::cout << " &#8674; ";
1862 }
1863
1864 std::cout << "<code>" << *i << "</code>";
1865 }
1866
1867 std::cout << "</li>\n";
1868 }
1869 };
1870
1871 static void output_module_subset_report( std::string const & module, bool track_sources, bool track_tests, bool html )
1872 {
1873 if( html )
1874 {
1875 module_subset_html_actions actions;
1876 output_module_subset_report( module, track_sources, track_tests, actions );
1877 }
1878 else
1879 {
1880 module_subset_txt_actions actions;
1881 output_module_subset_report( module, track_sources, track_tests, actions );
1882 }
1883 }
1884
1885 // --list-exceptions
1886
1887 static void list_exceptions()
1888 {
1889 std::string lm;
1890
1891 for( std::map< std::string, std::set<std::string> >::const_iterator i = s_module_headers.begin(); i != s_module_headers.end(); ++i )
1892 {
1893 std::string module = i->first;
1894
1895 std::replace( module.begin(), module.end(), '~', '/' );
1896
1897 std::string const prefix = "boost/" + module;
1898 size_t const n = prefix.size();
1899
1900 for( std::set< std::string >::const_iterator j = i->second.begin(); j != i->second.end(); ++j )
1901 {
1902 std::string const & header = *j;
1903
1904 if( header.substr( 0, n+1 ) != prefix + '/' && header != prefix + ".hpp" )
1905 {
1906 if( lm != module )
1907 {
1908 std::cout << module << ":\n";
1909 lm = module;
1910 }
1911
1912 std::cout << " " << header << '\n';
1913 }
1914 }
1915 }
1916 }
1917
1918 // --test
1919
1920 struct module_test_primary_actions: public module_primary_actions
1921 {
1922 std::set< std::string > & m_;
1923
1924 module_test_primary_actions( std::set< std::string > & m ): m_( m )
1925 {
1926 }
1927
1928 void heading( std::string const & module )
1929 {
1930 std::cout << "Test dependencies for " << module << ":\n\n";
1931 }
1932
1933 void module_start( std::string const & module )
1934 {
1935 std::cout << module << "\n";
1936 m_.insert( module );
1937 }
1938
1939 void module_end( std::string const & /*module*/ )
1940 {
1941 }
1942
1943 void header_start( std::string const & /*header*/ )
1944 {
1945 }
1946
1947 void header_end( std::string const & /*header*/ )
1948 {
1949 }
1950
1951 void from_header( std::string const & /*header*/ )
1952 {
1953 }
1954 };
1955
1956 struct module_test_secondary_actions: public module_secondary_actions
1957 {
1958 std::set< std::string > & m_;
1959 std::string m2_;
1960
1961 module_test_secondary_actions( std::set< std::string > & m ): m_( m )
1962 {
1963 }
1964
1965 void heading( std::string const & /*module*/ )
1966 {
1967 }
1968
1969 void module_start( std::string const & module )
1970 {
1971 m2_ = module;
1972 }
1973
1974 void module_end( std::string const & /*module*/ )
1975 {
1976 }
1977
1978 void module_adds( std::string const & module )
1979 {
1980 if( m_.count( module ) == 0 )
1981 {
1982 std::cout << module << " (from " << m2_ << ")\n";
1983 m_.insert( module );
1984 }
1985 }
1986 };
1987
1988 static void output_module_test_report( std::string const & module )
1989 {
1990 std::set< std::string > m;
1991
1992 module_test_primary_actions a1( m );
1993 output_module_primary_report( module, a1, true, true );
1994
1995 std::cout << "\n";
1996
1997 bool secondary = false;
1998 enable_secondary( secondary, true, false );
1999
2000 std::set< std::string > m2( m );
2001 m2.insert( module );
2002
2003 module_test_secondary_actions a2( m2 );
2004
2005 output_module_secondary_report( module, m, a2 );
2006 }
2007
2008 // --cmake
2009
2010 struct collect_primary_dependencies: public module_primary_actions
2011 {
2012 std::set< std::string > set_;
2013
2014 void heading( std::string const & )
2015 {
2016 }
2017
2018 void module_start( std::string const & module )
2019 {
2020 if( module == "(unknown)" ) return;
2021
2022 set_.insert( module );
2023 }
2024
2025 void module_end( std::string const & /*module*/ )
2026 {
2027 }
2028
2029 void header_start( std::string const & /*header*/ )
2030 {
2031 }
2032
2033 void header_end( std::string const & /*header*/ )
2034 {
2035 }
2036
2037 void from_header( std::string const & /*header*/ )
2038 {
2039 }
2040 };
2041
2042 static std::string module_cmake_name( std::string module )
2043 {
2044 std::replace( module.begin(), module.end(), '~', '_' );
2045 return module;
2046 }
2047
2048 static void output_module_cmake_report( std::string module )
2049 {
2050 std::cout << "# Generated by `boostdep --cmake " << module << "`\n\n";
2051
2052 std::replace( module.begin(), module.end(), '/', '~' );
2053
2054 collect_primary_dependencies a1;
2055 output_module_primary_report( module, a1, false, false );
2056
2057 if( !fs::exists( module_source_path( module ) ) )
2058 {
2059 for( std::set< std::string >::const_iterator i = a1.set_.begin(); i != a1.set_.end(); ++i )
2060 {
2061 std::cout << "boost_declare_dependency(INTERFACE " << module_cmake_name( *i ) << ")\n";
2062 }
2063 }
2064 else
2065 {
2066 collect_primary_dependencies a2;
2067 output_module_primary_report( module, a2, true, false );
2068
2069 for( std::set< std::string >::const_iterator i = a1.set_.begin(); i != a1.set_.end(); ++i )
2070 {
2071 a2.set_.erase( *i );
2072 std::cout << "boost_declare_dependency(PUBLIC " << module_cmake_name( *i ) << ")\n";
2073 }
2074
2075 std::cout << "\n";
2076
2077 for( std::set< std::string >::const_iterator i = a2.set_.begin(); i != a2.set_.end(); ++i )
2078 {
2079 std::cout << "boost_declare_dependency(PRIVATE " << module_cmake_name( *i ) << ")\n";
2080 }
2081 }
2082 }
2083
2084 // --list-missing-headers
2085
2086 struct missing_header_actions: public module_primary_actions
2087 {
2088 std::string module_, module2_;
2089
2090 void heading( std::string const & module )
2091 {
2092 module_ = module;
2093 }
2094
2095 void module_start( std::string const & module )
2096 {
2097 module2_ = module;
2098 }
2099
2100 void module_end( std::string const & /*module*/ )
2101 {
2102 }
2103
2104 void header_start( std::string const & header )
2105 {
2106 if( module2_ == "(unknown)" )
2107 {
2108 if( !module_.empty() )
2109 {
2110 std::cout << module_ << ":\n";
2111 module_.clear();
2112 }
2113
2114 std::cout << " <" << header << ">\n";
2115 }
2116 }
2117
2118 void header_end( std::string const & /*header*/ )
2119 {
2120 }
2121
2122 void from_header( std::string const & header )
2123 {
2124 if( module2_ == "(unknown)" )
2125 {
2126 std::cout << " from <" << header << ">\n";
2127 }
2128 }
2129 };
2130
2131 static void list_missing_headers( std::string const & module )
2132 {
2133 missing_header_actions a;
2134 output_module_primary_report( module, a, false, false );
2135 }
2136
2137 static void list_missing_headers()
2138 {
2139 for( std::set< std::string >::const_iterator i = s_modules.begin(); i != s_modules.end(); ++i )
2140 {
2141 list_missing_headers( *i );
2142 }
2143 }
2144
2145 // --pkgconfig
2146
2147 struct primary_pkgconfig_actions: public module_primary_actions
2148 {
2149 std::string version_;
2150 std::string list_;
2151
2152 void heading( std::string const & )
2153 {
2154 }
2155
2156 void module_start( std::string const & module )
2157 {
2158 if( module == "(unknown)" ) return;
2159
2160 std::string m2( module );
2161 std::replace( m2.begin(), m2.end(), '~', '_' );
2162
2163 if( !list_.empty() )
2164 {
2165 list_ += ", ";
2166 }
2167
2168 list_ += "boost_" + m2 + " = " + version_;
2169 }
2170
2171 void module_end( std::string const & )
2172 {
2173 }
2174
2175 void header_start( std::string const & )
2176 {
2177 }
2178
2179 void header_end( std::string const & )
2180 {
2181 }
2182
2183 void from_header( std::string const & )
2184 {
2185 }
2186 };
2187
2188 static void output_requires( std::string const & section, std::string const & version, std::set< std::string > const & s )
2189 {
2190 bool first = true;
2191
2192 for( std::set< std::string >::const_iterator i = s.begin(); i != s.end(); ++i )
2193 {
2194 if( first )
2195 {
2196 std::cout << section << ": ";
2197 first = false;
2198 }
2199 else
2200 {
2201 std::cout << ", ";
2202 }
2203
2204 std::string m2( *i );
2205 std::replace( m2.begin(), m2.end(), '~', '_' );
2206
2207 std::cout << "boost_" << m2 << " = " << version;
2208 }
2209 }
2210
2211 static void output_pkgconfig( std::string const & module, std::string const & version, int argc, char const* argv[] )
2212 {
2213 for( int i = 0; i < argc; ++i )
2214 {
2215 std::cout << argv[ i ] << '\n';
2216 }
2217
2218 std::cout << '\n';
2219
2220 std::string m2( module );
2221 std::replace( m2.begin(), m2.end(), '/', '_' );
2222
2223 std::string m3( module );
2224 std::replace( m3.begin(), m3.end(), '/', '~' );
2225
2226 std::cout << "Name: boost_" << module << '\n';
2227 std::cout << "Description: Boost C++ library '" << module << "'\n";
2228 std::cout << "Version: " << version << '\n';
2229 std::cout << "URL: http://www.boost.org/libs/" << module << '\n';
2230 std::cout << "Cflags: -I${includedir}\n";
2231
2232 if( fs::exists( module_build_path( module ) ) && fs::exists( module_source_path( module ) ) )
2233 {
2234 std::cout << "Libs: -L${libdir} -lboost_" << m2 << "\n";
2235 }
2236
2237 collect_primary_dependencies a1;
2238 output_module_primary_report( m3, a1, false, false );
2239
2240 if( !a1.set_.empty() )
2241 {
2242 output_requires( "Requires", version, a1.set_ );
2243 std::cout << std::endl;
2244 }
2245
2246 collect_primary_dependencies a2;
2247 output_module_primary_report( m3, a2, true, false );
2248
2249 for( std::set< std::string >::const_iterator i = a1.set_.begin(); i != a1.set_.end(); ++i )
2250 {
2251 a2.set_.erase( *i );
2252 }
2253
2254 if( !a2.set_.empty() )
2255 {
2256 output_requires( "Requires.private", version, a2.set_ );
2257 std::cout << std::endl;
2258 }
2259 }
2260
2261 // --subset-for
2262
2263 static void output_directory_subset_report( std::string const & module, std::set<std::string> const & headers, bool html )
2264 {
2265 for( std::set<std::string>::const_iterator i = headers.begin(); i != headers.end(); ++i )
2266 {
2267 std::map< std::string, std::set< std::string > > deps;
2268 std::map< std::string, std::set< std::string > > from;
2269
2270 std::ifstream is( i->c_str() );
2271 scan_header_dependencies( *i, is, deps, from );
2272
2273 for( std::map< std::string, std::set< std::string > >::const_iterator j = from.begin(); j != from.end(); ++j )
2274 {
2275 for( std::set<std::string>::const_iterator k = j->second.begin(); k != j->second.end(); ++k )
2276 {
2277 s_header_includes[ *k ].insert( j->first );
2278 }
2279 }
2280 }
2281
2282 if( html )
2283 {
2284 module_subset_html_actions actions;
2285 output_module_subset_report_( module, headers, actions );
2286 }
2287 else
2288 {
2289 module_subset_txt_actions actions;
2290 output_module_subset_report_( module, headers, actions );
2291 }
2292 }
2293
2294 // list_buildable_dependencies
2295
2296 struct list_buildable_dependencies_actions: public module_overview_actions
2297 {
2298 std::set< std::string > buildable_;
2299
2300 std::set< std::string > deps_;
2301 bool headers_;
2302
2303 list_buildable_dependencies_actions(): headers_()
2304 {
2305 }
2306
2307 void begin()
2308 {
2309 std::cout << "# Generated by `boostdep --list-buildable-dependencies`\n\n";
2310 }
2311
2312 void end()
2313 {
2314 }
2315
2316 void module_start( std::string const & module )
2317 {
2318 deps_.clear();
2319 headers_ = false;
2320
2321 if( buildable_.count( module ) )
2322 {
2323 std::cout << module << " =";
2324 }
2325 }
2326
2327 void module_end( std::string const & module )
2328 {
2329 if( buildable_.count( module ) )
2330 {
2331 if( headers_ )
2332 {
2333 std::cout << " headers";
2334 }
2335
2336 for( std::set< std::string >::iterator i = deps_.begin(); i != deps_.end(); ++i )
2337 {
2338 std::cout << " " << *i;
2339 }
2340
2341 std::cout << " ;\n";
2342 }
2343 }
2344
2345 void module2( std::string const & module )
2346 {
2347 if( module == "(unknown)" ) return;
2348
2349 if( buildable_.count( module ) == 0 )
2350 {
2351 headers_ = true;
2352 }
2353 else
2354 {
2355 deps_.insert( module );
2356 }
2357 }
2358 };
2359
2360 static void list_buildable_dependencies()
2361 {
2362 list_buildable_dependencies_actions actions;
2363
2364 for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
2365 {
2366 if( fs::exists( module_build_path( *i ) ) && fs::exists( module_source_path( *i ) ) )
2367 {
2368 actions.buildable_.insert( *i );
2369 }
2370 }
2371
2372 output_module_overview_report( actions );
2373 }
2374
2375 //
2376
2377 static bool find_boost_root()
2378 {
2379 for( int i = 0; i < 32; ++i )
2380 {
2381 if( fs::exists( "Jamroot" ) )
2382 {
2383 return true;
2384 }
2385
2386 fs::path p = fs::current_path();
2387
2388 if( p == p.root_path() )
2389 {
2390 return false;
2391 }
2392
2393 fs::current_path( p.parent_path() );
2394 }
2395
2396 return false;
2397 }
2398
2399 static bool is_boost_root( fs::path const & p )
2400 {
2401 return fs::exists( p / "Jamroot" );
2402 }
2403
2404 // teebuf
2405
2406 class teebuf: public std::streambuf
2407 {
2408 private:
2409
2410 std::streambuf * sb1_;
2411 std::streambuf * sb2_;
2412
2413 public:
2414
2415 teebuf( std::streambuf * sb1, std::streambuf * sb2 ): sb1_( sb1 ), sb2_( sb2 )
2416 {
2417 }
2418
2419 private:
2420
2421 virtual int overflow( int c )
2422 {
2423 int r1 = sb1_->sputc( c );
2424 int r2 = sb2_->sputc( c );
2425
2426 return r1 == EOF || r2 == EOF? EOF : c;
2427 }
2428
2429 virtual int sync()
2430 {
2431 int r1 = sb1_->pubsync();
2432 int r2 = sb2_->pubsync();
2433
2434 return r1 == 0 && r2 == 0? 0 : -1;
2435 }
2436 };
2437
2438 // save_cout_rdbuf
2439
2440 class save_cout_rdbuf
2441 {
2442 private:
2443
2444 std::streambuf * sb_;
2445
2446 public:
2447
2448 save_cout_rdbuf(): sb_( std::cout.rdbuf() )
2449 {
2450 }
2451
2452 ~save_cout_rdbuf()
2453 {
2454 std::cout.rdbuf( sb_ );
2455 }
2456 };
2457
2458 // main
2459
2460 int main( int argc, char const* argv[] )
2461 {
2462 if( argc < 2 )
2463 {
2464 std::cout <<
2465
2466 "Usage:\n"
2467 "\n"
2468 " boostdep --list-modules\n"
2469 " boostdep --list-buildable\n"
2470 " boostdep [--track-sources] [--track-tests] --list-dependencies\n"
2471 " boostdep --list-exceptions\n"
2472 " boostdep --list-missing-headers\n"
2473 " boostdep --list-buildable-dependencies\n"
2474 "\n"
2475 " boostdep [options] --module-overview\n"
2476 " boostdep [options] --module-levels\n"
2477 " boostdep [options] --module-weights\n"
2478 "\n"
2479 " boostdep [options] [--primary] <module>\n"
2480 " boostdep [options] --secondary <module>\n"
2481 " boostdep [options] --reverse <module>\n"
2482 " boostdep [options] --subset <module>\n"
2483 " boostdep [options] [--header] <header>\n"
2484 " boostdep --test <module>\n"
2485 " boostdep --cmake <module>\n"
2486 " boostdep --pkgconfig <module> <version> [<var>=<value>] [<var>=<value>]...\n"
2487 " boostdep [options] --subset-for <directory>\n"
2488 "\n"
2489 " [options]: [--boost-root <path-to-boost>]\n"
2490 " [--[no-]track-sources] [--[no-]track-tests]\n"
2491 " [--html-title <title>] [--html-footer <footer>]\n"
2492 " [--html-stylesheet <stylesheet>] [--html-prefix <prefix>]\n"
2493 " [--html]\n";
2494
2495 return -1;
2496 }
2497
2498 bool root_set = false;
2499
2500 for( int i = 0; i < argc; ++i )
2501 {
2502 std::string option = argv[ i ];
2503
2504 if( option == "--boost-root" )
2505 {
2506 if( i + 1 < argc )
2507 {
2508 fs::path p( argv[ ++i ] );
2509
2510 if( is_boost_root( p ) )
2511 {
2512 fs::current_path( p );
2513 root_set = true;
2514 }
2515 else
2516 {
2517 std::cerr << "'" << p.string() << "': not a valid Boost root.\n";
2518 return -2;
2519 }
2520 }
2521 else
2522 {
2523 std::cerr << "'" << option << "': missing argument.\n";
2524 return -2;
2525 }
2526 }
2527 }
2528
2529 if( !root_set && !find_boost_root() )
2530 {
2531 char const * env_root = std::getenv( "BOOST_ROOT" );
2532
2533 if( env_root && is_boost_root( env_root ) )
2534 {
2535 fs::current_path( env_root );
2536 }
2537 else
2538 {
2539 std::cerr << "boostdep: Could not find Boost root.\n";
2540 return -2;
2541 }
2542 }
2543
2544 try
2545 {
2546 build_header_map();
2547 }
2548 catch( fs::filesystem_error const & x )
2549 {
2550 std::cerr << x.what() << std::endl;
2551 }
2552
2553 bool html = false;
2554 bool secondary = false;
2555 bool track_sources = false;
2556 bool track_tests = false;
2557
2558 std::string html_title = "Boost Dependency Report";
2559 std::string html_footer;
2560 std::string html_stylesheet;
2561 std::string html_prefix;
2562
2563 std::ostringstream captured_output;
2564 teebuf tsb( std::cout.rdbuf(), captured_output.rdbuf() );
2565
2566 save_cout_rdbuf scrdb;
2567
2568 for( int i = 1; i < argc; ++i )
2569 {
2570 std::string option = argv[ i ];
2571
2572 if( option == "--boost-root" )
2573 {
2574 ++i;
2575 }
2576 else if( option == "--list-modules" )
2577 {
2578 list_modules();
2579 }
2580 else if( option == "--list-buildable" )
2581 {
2582 list_buildable();
2583 }
2584 else if( option == "--title" || option == "--html-title" )
2585 {
2586 if( i + 1 < argc )
2587 {
2588 html_title = argv[ ++i ];
2589 }
2590 }
2591 else if( option == "--footer" || option == "--html-footer" )
2592 {
2593 if( i + 1 < argc )
2594 {
2595 html_footer = argv[ ++i ];
2596 }
2597 }
2598 else if( option == "--html-stylesheet" )
2599 {
2600 if( i + 1 < argc )
2601 {
2602 html_stylesheet = argv[ ++i ];
2603 }
2604 }
2605 else if( option == "--html-prefix" )
2606 {
2607 if( i + 1 < argc )
2608 {
2609 html_prefix = argv[ ++i ];
2610 }
2611 }
2612 else if( option == "--html" )
2613 {
2614 if( !html )
2615 {
2616 html = true;
2617 output_html_header( html_title, html_stylesheet, html_prefix );
2618 }
2619 }
2620 else if( option == "--track-sources" )
2621 {
2622 track_sources = true;
2623 }
2624 else if( option == "--no-track-sources" )
2625 {
2626 track_sources = false;
2627 }
2628 else if( option == "--track-tests" )
2629 {
2630 track_tests = true;
2631 }
2632 else if( option == "--no-track-tests" )
2633 {
2634 track_tests = false;
2635 }
2636 else if( option == "--primary" )
2637 {
2638 if( i + 1 < argc )
2639 {
2640 output_module_primary_report( argv[ ++i ], html, track_sources, track_tests );
2641 }
2642 }
2643 else if( option == "--secondary" )
2644 {
2645 if( i + 1 < argc )
2646 {
2647 enable_secondary( secondary, track_sources, track_tests );
2648 output_module_secondary_report( argv[ ++i ], html );
2649 }
2650 }
2651 else if( option == "--reverse" )
2652 {
2653 if( i + 1 < argc )
2654 {
2655 enable_secondary( secondary, track_sources, track_tests );
2656 output_module_reverse_report( argv[ ++i ], html );
2657 }
2658 }
2659 else if( option == "--header" )
2660 {
2661 if( i + 1 < argc )
2662 {
2663 enable_secondary( secondary, track_sources, track_tests );
2664 output_header_report( argv[ ++i ], html );
2665 }
2666 }
2667 else if( option == "--subset" )
2668 {
2669 if( i + 1 < argc )
2670 {
2671 enable_secondary( secondary, track_sources, track_tests );
2672 output_module_subset_report( argv[ ++i ], track_sources, track_tests, html );
2673 }
2674 }
2675 else if( option == "--test" )
2676 {
2677 if( i + 1 < argc )
2678 {
2679 output_module_test_report( argv[ ++i ] );
2680 }
2681 }
2682 else if( option == "--cmake" )
2683 {
2684 if( i + 1 < argc )
2685 {
2686 output_module_cmake_report( argv[ ++i ] );
2687 }
2688 }
2689 else if( option == "--module-levels" )
2690 {
2691 enable_secondary( secondary, track_sources, track_tests );
2692 output_module_level_report( html );
2693 }
2694 else if( option == "--module-overview" )
2695 {
2696 enable_secondary( secondary, track_sources, track_tests );
2697 output_module_overview_report( html );
2698 }
2699 else if( option == "--module-weights" )
2700 {
2701 enable_secondary( secondary, track_sources, track_tests );
2702 output_module_weight_report( html );
2703 }
2704 else if( option == "--list-dependencies" )
2705 {
2706 enable_secondary( secondary, track_sources, track_tests );
2707 list_dependencies();
2708 }
2709 else if( option == "--list-exceptions" )
2710 {
2711 list_exceptions();
2712 }
2713 else if( option == "--list-missing-headers" )
2714 {
2715 list_missing_headers();
2716 }
2717 else if( option == "--pkgconfig" )
2718 {
2719 if( i + 2 < argc )
2720 {
2721 std::string module = argv[ ++i ];
2722 std::string version = argv[ ++i ];
2723
2724 ++i;
2725
2726 output_pkgconfig( module, version, argc - i, argv + i );
2727 }
2728 else
2729 {
2730 std::cerr << "'" << option << "': missing module or version.\n";
2731 }
2732
2733 break;
2734 }
2735 else if( option == "--subset-for" )
2736 {
2737 if( i + 1 < argc )
2738 {
2739 std::string module = argv[ ++i ];
2740
2741 enable_secondary( secondary, track_sources, track_tests );
2742
2743 std::set<std::string> headers;
2744 add_module_headers( module, headers );
2745
2746 output_directory_subset_report( module, headers, html );
2747 }
2748 else
2749 {
2750 std::cerr << "'" << option << "': missing argument.\n";
2751 }
2752
2753 break;
2754 }
2755 else if( option == "--list-buildable-dependencies" )
2756 {
2757 enable_secondary( secondary, true, false );
2758 list_buildable_dependencies();
2759 }
2760 else if( option == "--capture-output" )
2761 {
2762 std::cout.rdbuf( &tsb );
2763 }
2764 else if( option == "--compare-output" )
2765 {
2766 if( i + 1 < argc )
2767 {
2768 std::string fn = argv[ ++i ];
2769 std::fstream is( fn.c_str() );
2770
2771 if( !is )
2772 {
2773 std::cerr << option << " '" << fn << "': could not open file.\n";
2774 return 1;
2775 }
2776
2777 std::istreambuf_iterator<char> first( is ), last;
2778 std::string fc( first, last );
2779
2780 if( fc != captured_output.str() )
2781 {
2782 std::cerr << option << " '" << fn << "': output does not match; expected output:\n---\n" << fc << "---\n";
2783 return 1;
2784 }
2785
2786 std::cerr << option << " '" << fn << "': output matches.\n";
2787 captured_output.str( "" );
2788 }
2789 else
2790 {
2791 std::cerr << "'" << option << "': missing argument.\n";
2792 return 1;
2793 }
2794 }
2795 else if( s_modules.count( option ) )
2796 {
2797 output_module_primary_report( option, html, track_sources, track_tests );
2798 }
2799 else if( s_header_map.count( option ) )
2800 {
2801 enable_secondary( secondary, track_sources, track_tests );
2802 output_header_report( option, html );
2803 }
2804 else
2805 {
2806 std::cerr << "'" << option << "': not an option, module or header.\n";
2807 }
2808 }
2809
2810 if( html )
2811 {
2812 output_html_footer( html_footer );
2813 }
2814 }