1 // inspect program -------------------------------------------------------------------//
2
3 // Copyright Beman Dawes 2002.
4 // Copyright Rene Rivera 2004-2006.
5 // Copyright Gennaro Prota 2006.
6
7 // Distributed under the Boost Software License, Version 1.0.
8 // (See accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10
11 // This program recurses through sub-directories looking for various problems.
12 // It contains some Boost specific features, like ignoring "bin",
13 // and the code that identifies library names assumes the Boost directory
14 // structure.
15
16 // See http://www.boost.org/tools/inspect/ for more information.
17
18 const char* boost_no_inspect = "boost-" "no-inspect";
19
20 // Directories with a file name of the boost_no_inspect value are not inspected.
21 // Files that contain the boost_no_inspect value are not inspected.
22
23
24 #include <vector>
25 #include <list>
26 #include <algorithm>
27 #include <cstring>
28
29 #include "boost/shared_ptr.hpp"
30 #include "boost/lexical_cast.hpp"
31 #include "boost/filesystem/operations.hpp"
32 #include "boost/filesystem/fstream.hpp"
33
34 #include <stdio.h> // for popen, pclose
35 #if defined(_MSC_VER)
36 # define POPEN _popen
37 # define PCLOSE _pclose
38 #else
39 # define POPEN popen
40 # define PCLOSE pclose
41 #endif
42
43 #include "time_string.hpp"
44
45 #include "inspector.hpp"
46
47 // the inspectors
48 #include "copyright_check.hpp"
49 #include "crlf_check.hpp"
50 #include "end_check.hpp"
51 #include "license_check.hpp"
52 #include "link_check.hpp"
53 #include "path_name_check.hpp"
54 #include "tab_check.hpp"
55 #include "ascii_check.hpp"
56 #include "apple_macro_check.hpp"
57 #include "assert_macro_check.hpp"
58 #include "deprecated_macro_check.hpp"
59 #include "minmax_check.hpp"
60 #include "unnamed_namespace_check.hpp"
61
62 #if !defined(INSPECT_USE_BOOST_TEST)
63 #define INSPECT_USE_BOOST_TEST 0
64 #endif
65
66 #if INSPECT_USE_BOOST_TEST
67 #include "boost/test/included/prg_exec_monitor.hpp"
68 #endif
69
70 namespace fs = boost::filesystem;
71
72 using namespace boost::inspect;
73
74 namespace
75 {
76 fs::path search_root = fs::initial_path();
77
78 class inspector_element
79 {
80 typedef boost::shared_ptr< boost::inspect::inspector > inspector_ptr;
81
82 public:
83 inspector_ptr inspector;
84 explicit
inspector_element(boost::inspect::inspector * p)85 inspector_element( boost::inspect::inspector * p ) : inspector(p) {}
86 };
87
88 typedef std::list< inspector_element > inspector_list;
89
90 long file_count = 0;
91 long directory_count = 0;
92 long error_count = 0;
93 const int max_offenders = 5; // maximum "worst offenders" to display
94
95 boost::inspect::string_set content_signatures;
96
97 struct error_msg
98 {
99 string library;
100 string rel_path;
101 string msg;
102 int line_number;
103
operator <__anonc4c2b3040111::error_msg104 bool operator<( const error_msg & rhs ) const
105 {
106 if ( library < rhs.library ) return true;
107 if ( library > rhs.library ) return false;
108 if ( rel_path < rhs.rel_path ) return true;
109 if ( rel_path > rhs.rel_path ) return false;
110 if ( line_number < rhs.line_number ) return true;
111 if ( line_number > rhs.line_number ) return false;
112 return msg < rhs.msg;
113 }
114 };
115
116 typedef std::vector< error_msg > error_msg_vector;
117 error_msg_vector msgs;
118
119 struct lib_error_count
120 {
121 int error_count;
122 string library;
123
operator <__anonc4c2b3040111::lib_error_count124 bool operator<( const lib_error_count & rhs ) const
125 {
126 return error_count > rhs.error_count;
127 }
128 };
129
130 typedef std::vector< lib_error_count > lib_error_count_vector;
131 lib_error_count_vector libs;
132
133 // visit_predicate (determines which directories are visited) --------------//
134
135 typedef bool(*pred_type)(const path&);
136
visit_predicate(const path & pth)137 bool visit_predicate( const path & pth )
138 {
139 string local( boost::inspect::relative_to( pth, search_root_path() ) );
140 string leaf( pth.leaf().string() );
141 if (leaf[0] == '.') // ignore hidden by convention directories such as
142 return false; // .htaccess, .git, .svn, .bzr, .DS_Store, etc.
143
144 return
145 // don't look at binaries
146 leaf != "bin"
147 && leaf != "bin.v2"
148 // no point in checking doxygen xml output
149 && local.find("doc/xml") != 0
150 && local.find("doc\\xml") != 0
151 // ignore if tag file present
152 && !boost::filesystem::exists(pth / boost_no_inspect)
153 ;
154 }
155
156 // library_from_content ----------------------------------------------------//
157
library_from_content(const string & content)158 string library_from_content( const string & content )
159 {
160 const string unknown_library ( "unknown" );
161 const string lib_root ( "www.boost.org/libs/" );
162 string::size_type pos( content.find( lib_root ) );
163
164 string lib = unknown_library;
165
166 if ( pos != string::npos ) {
167
168 pos += lib_root.length();
169
170 const char delims[] = " " // space and...
171 "/\n\r\t";
172
173 string::size_type n = content.find_first_of( string(delims), pos );
174 if (n != string::npos)
175 lib = string(content, pos, n - pos);
176
177 }
178
179 return lib;
180 }
181
182 // find_signature ----------------------------------------------------------//
183
find_signature(const path & file_path,const boost::inspect::string_set & signatures)184 bool find_signature( const path & file_path,
185 const boost::inspect::string_set & signatures )
186 {
187 string name( file_path.leaf().string() );
188 if ( signatures.find( name ) == signatures.end() )
189 {
190 string::size_type pos( name.rfind( '.' ) );
191 if ( pos == string::npos
192 || signatures.find( name.substr( pos ) )
193 == signatures.end() ) return false;
194 }
195 return true;
196 }
197
198 // load_content ------------------------------------------------------------//
199
load_content(const path & file_path,string & target)200 void load_content( const path & file_path, string & target )
201 {
202 target = "";
203
204 if ( !find_signature( file_path, content_signatures ) ) return;
205
206 fs::ifstream fin( file_path, std::ios_base::in|std::ios_base::binary );
207 if ( !fin )
208 throw string( "could not open input file: " ) + file_path.string();
209 std::getline( fin, target, '\0' ); // read the whole file
210 }
211
212 // check -------------------------------------------------------------------//
213
check(const string & lib,const path & pth,const string & content,const inspector_list & insp_list)214 void check( const string & lib,
215 const path & pth, const string & content, const inspector_list & insp_list )
216 {
217 // invoke each inspector
218 for ( inspector_list::const_iterator itr = insp_list.begin();
219 itr != insp_list.end(); ++itr )
220 {
221 itr->inspector->inspect( lib, pth ); // always call two-argument form
222 if ( find_signature( pth, itr->inspector->signatures() ) )
223 {
224 itr->inspector->inspect( lib, pth, content );
225 }
226 }
227 }
228
229 // visit_all ---------------------------------------------------------------//
230
231 template< class DirectoryIterator >
visit_all(const string & lib,const path & dir_path,const inspector_list & insps)232 void visit_all( const string & lib,
233 const path & dir_path, const inspector_list & insps )
234 {
235 static DirectoryIterator end_itr;
236 ++directory_count;
237
238 for ( DirectoryIterator itr( dir_path ); itr != end_itr; ++itr )
239 {
240 if ( fs::is_directory( *itr ) )
241 {
242 if ( visit_predicate( *itr ) )
243 {
244 string cur_lib( boost::inspect::impute_library( *itr ) );
245 check( cur_lib, *itr, "", insps );
246 visit_all<DirectoryIterator>( cur_lib, *itr, insps );
247 }
248 }
249 else if (itr->path().leaf().string()[0] != '.') // ignore if hidden
250 {
251 ++file_count;
252 string content;
253 load_content( *itr, content );
254 if (content.find(boost_no_inspect) == string::npos)
255 check( lib.empty() ? library_from_content( content ) : lib,
256 *itr, content, insps );
257 }
258 }
259 }
260
261 // display -----------------------------------------------------------------//
262
263 enum display_format_type
264 {
265 display_html, display_text
266 }
267 display_format = display_html;
268
269 enum display_mode_type
270 {
271 display_full, display_brief
272 }
273 display_mode = display_full;
274
275 // display_summary_helper --------------------------------------------------//
276
display_summary_helper(const string & current_library,int err_count)277 void display_summary_helper( const string & current_library, int err_count )
278 {
279 if (display_format == display_text)
280 {
281 std::cout << " " << current_library << " (" << err_count << ")\n";
282 }
283 else
284 {
285 std::cout
286 << " <a href=\"#"
287 << current_library // what about malformed for URI refs? [gps]
288 << "\">" << current_library
289 << "</a> ("
290 << err_count << ")<br>\n";
291 }
292 }
293
294 // display_summary ---------------------------------------------------------//
295
display_summary()296 void display_summary()
297 {
298 if (display_format == display_text)
299 {
300 std::cout << "Summary:\n";
301 }
302 else
303 {
304 std::cout <<
305 "<h2>Summary</h2>\n"
306 "<blockquote>\n"
307 ;
308 }
309
310 string current_library( msgs.begin()->library );
311 int err_count = 0;
312 for ( error_msg_vector::iterator itr ( msgs.begin() );
313 itr != msgs.end(); ++itr )
314 {
315 if ( current_library != itr->library )
316 {
317 display_summary_helper( current_library, err_count );
318 current_library = itr->library;
319 err_count = 0;
320 }
321 ++err_count;
322 }
323 display_summary_helper( current_library, err_count );
324
325 if (display_format == display_text)
326 std::cout << "\n";
327 else
328 std::cout << "</blockquote>\n";
329 }
330
331 // html_encode -------------------------------------------------------------//
332
html_encode(std::string const & text)333 std::string html_encode(std::string const& text)
334 {
335 std::string result;
336
337 for(std::string::const_iterator it = text.begin(),
338 end = text.end(); it != end; ++it)
339 {
340 switch(*it) {
341 case '<':
342 result += "<";
343 break;
344 case '>':
345 result += ">";
346 break;
347 case '&':
348 result += "&";
349 break;
350 default:
351 result += *it;
352 }
353 }
354
355 return result;
356 }
357
358 // display_details ---------------------------------------------------------//
359
display_details()360 void display_details()
361 {
362 if (display_format == display_text)
363 {
364 // display error messages with group indication
365 error_msg current;
366 string sep;
367 for ( error_msg_vector::iterator itr ( msgs.begin() );
368 itr != msgs.end(); ++itr )
369 {
370 if ( current.library != itr->library )
371 {
372 if ( display_full == display_mode )
373 std::cout << "\n|" << itr->library << "|\n";
374 else
375 std::cout << "\n\n|" << itr->library << '|';
376 }
377
378 if ( current.library != itr->library
379 || current.rel_path != itr->rel_path )
380 {
381 if ( display_full == display_mode )
382 {
383 std::cout << " " << itr->rel_path << ":\n";
384 }
385 else
386 {
387 path current_rel_path(current.rel_path);
388 path this_rel_path(itr->rel_path);
389 if (current_rel_path.branch_path() != this_rel_path.branch_path())
390 {
391 std::cout << "\n " << this_rel_path.branch_path().string() << '/';
392 }
393 std::cout << "\n " << this_rel_path.leaf() << ':';
394 }
395 }
396 if ( current.library != itr->library
397 || current.rel_path != itr->rel_path
398 || current.msg != itr->msg )
399 {
400 const string m = itr->msg;
401
402 if ( display_full == display_mode )
403 std::cout << " " << m << '\n';
404 else
405 std::cout << ' ' << m;
406 }
407 current.library = itr->library;
408 current.rel_path = itr->rel_path;
409 current.msg = itr->msg;
410 }
411 std::cout << "\n";
412 }
413 else // html
414 {
415 // display error messages with group indication
416 error_msg current;
417 bool first_sep = true;
418 bool first = true;
419 for ( error_msg_vector::iterator itr ( msgs.begin() );
420 itr != msgs.end(); ++itr )
421 {
422 if ( current.library != itr->library )
423 {
424 if ( !first ) std::cout << "</pre>\n";
425 std::cout << "\n<h3><a name=\"" << itr->library
426 << "\">" << itr->library << "</a></h3>\n<pre>";
427 }
428 if ( current.library != itr->library
429 || current.rel_path != itr->rel_path )
430 {
431 std::cout << "\n";
432 std::cout << itr->rel_path;
433 first_sep = true;
434 }
435 if ( current.library != itr->library
436 || current.rel_path != itr->rel_path
437 || current.msg != itr->msg )
438 {
439 std::string sep;
440 if (first_sep)
441 if (itr->line_number) sep = ":<br> ";
442 else sep = ": ";
443 else
444 if (itr->line_number) sep = "<br> ";
445 else sep = ", ";
446
447 // print the message
448 if (itr->line_number)
449 std::cout << sep << "(line " << itr->line_number << ") " << html_encode(itr->msg);
450 else std::cout << sep << html_encode(itr->msg);
451
452 first_sep = false;
453 }
454 current.library = itr->library;
455 current.rel_path = itr->rel_path;
456 current.msg = itr->msg;
457 first = false;
458 }
459 std::cout << "</pre>\n";
460 }
461 }
462
463
464 // worst_offenders_count_helper --------------------------------------------------//
465
worst_offenders_count_helper(const string & current_library,int err_count)466 void worst_offenders_count_helper( const string & current_library, int err_count )
467 {
468 lib_error_count lec;
469 lec.library = current_library;
470 lec.error_count = err_count;
471 libs.push_back( lec );
472 }
473 // worst_offenders_count -----------------------------------------------------//
474
worst_offenders_count()475 void worst_offenders_count()
476 {
477 if ( msgs.empty() )
478 {
479 return;
480 }
481 string current_library( msgs.begin()->library );
482 int err_count = 0;
483 for ( error_msg_vector::iterator itr ( msgs.begin() );
484 itr != msgs.end(); ++itr )
485 {
486 if ( current_library != itr->library )
487 {
488 worst_offenders_count_helper( current_library, err_count );
489 current_library = itr->library;
490 err_count = 0;
491 }
492 ++err_count;
493 }
494 worst_offenders_count_helper( current_library, err_count );
495 }
496
497 // display_worst_offenders -------------------------------------------------//
498
display_worst_offenders()499 void display_worst_offenders()
500 {
501 if (display_mode == display_brief)
502 return;
503 if (display_format == display_text)
504 {
505 std::cout << "Worst Offenders:\n";
506 }
507 else
508 {
509 std::cout <<
510 "<h2>Worst Offenders</h2>\n"
511 "<blockquote>\n"
512 ;
513 }
514
515 int display_count = 0;
516 int last_error_count = 0;
517 for ( lib_error_count_vector::iterator itr ( libs.begin() );
518 itr != libs.end()
519 && (display_count < max_offenders
520 || itr->error_count == last_error_count);
521 ++itr, ++display_count )
522 {
523 if (display_format == display_text)
524 {
525 std::cout << itr->library << " " << itr->error_count << "\n";
526 }
527 else
528 {
529 std::cout
530 << " <a href=\"#"
531 << itr->library
532 << "\">" << itr->library
533 << "</a> ("
534 << itr->error_count << ")<br>\n";
535 }
536 last_error_count = itr->error_count;
537 }
538
539 if (display_format == display_text)
540 std::cout << "\n";
541 else
542 std::cout << "</blockquote>\n";
543 }
544
545
options()546 const char * options()
547 {
548 return
549 " Output Options:\n\n"
550 " -brief\n"
551 " -text\n"
552 " -version-string <version message>\n"
553 "\n"
554 " Checks:\n\n"
555 " -license\n"
556 " -copyright\n"
557 " -crlf\n"
558 " -end\n"
559 " -link\n"
560 " -path_name\n"
561 " -tab\n"
562 " -ascii\n"
563 " -apple_macro\n"
564 " -assert_macro\n"
565 " -deprecated_macro\n"
566 " -minmax\n"
567 " -unnamed\n"
568 " -version-string <version message>\n"
569 " default is all checks on; otherwise options specify desired checks"
570 "\n";
571 }
572
doctype_declaration()573 const char * doctype_declaration()
574 {
575 return
576 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
577 "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"
578 ;
579 }
580
validator_link(const std::string & text)581 std::string validator_link(const std::string & text)
582 {
583 return
584 // with link to validation service
585 "<a href=\"http://validator.w3.org/check?uri=referer\">"
586 + text
587 + "</a>"
588 ;
589 }
590
591 } // unnamed namespace
592
593 namespace boost
594 {
595 namespace inspect
596 {
597
598 // line_break --------------------------------------------------------------//
599
line_break()600 const char * line_break()
601 {
602 return display_format ? "\n" : "<br>\n";
603 }
604
605 // search_root_path --------------------------------------------------------//
606
search_root_path()607 path search_root_path()
608 {
609 return search_root;
610 }
611
612 // register_signature ------------------------------------------------------//
613
register_signature(const string & signature)614 void inspector::register_signature( const string & signature )
615 {
616 m_signatures.insert( signature );
617 content_signatures.insert( signature );
618 }
619
620 // error -------------------------------------------------------------------//
621
error(const string & library_name,const path & full_path,const string & msg,int line_number)622 void inspector::error( const string & library_name,
623 const path & full_path, const string & msg, int line_number )
624 {
625 ++error_count;
626 error_msg err_msg;
627 err_msg.library = library_name;
628 err_msg.rel_path = relative_to( full_path, search_root_path() );
629 err_msg.msg = msg;
630 err_msg.line_number = line_number;
631 msgs.push_back( err_msg );
632
633 // std::cout << library_name << ": "
634 // << full_path.string() << ": "
635 // << msg << '\n';
636
637 }
638
source_inspector()639 source_inspector::source_inspector()
640 {
641 // C/C++ source code...
642 register_signature( ".c" );
643 register_signature( ".cpp" );
644 register_signature( ".css" );
645 register_signature( ".cxx" );
646 register_signature( ".h" );
647 register_signature( ".hpp" );
648 register_signature( ".hxx" );
649 register_signature( ".inc" );
650 register_signature( ".ipp" );
651
652 // Boost.Build BJam source code...
653 register_signature( "Jamfile" );
654 register_signature( ".jam" );
655 register_signature( ".v2" );
656
657 // Other scripts; Python, shell, autoconfig, etc.
658 register_signature( "configure.in" );
659 register_signature( "GNUmakefile" );
660 register_signature( "Makefile" );
661 register_signature( ".bat" );
662 register_signature( ".mak" );
663 register_signature( ".pl" );
664 register_signature( ".py" );
665 register_signature( ".sh" );
666
667 // Hypertext, Boost.Book, and other text...
668 register_signature( "news" );
669 register_signature( "readme" );
670 register_signature( "todo" );
671 register_signature( "NEWS" );
672 register_signature( "README" );
673 register_signature( "TODO" );
674 register_signature( ".boostbook" );
675 register_signature( ".htm" );
676 register_signature( ".html" );
677 register_signature( ".rst" );
678 register_signature( ".sgml" );
679 register_signature( ".shtml" );
680 register_signature( ".txt" );
681 register_signature( ".xml" );
682 register_signature( ".xsd" );
683 register_signature( ".xsl" );
684 register_signature( ".qbk" );
685 }
686
hypertext_inspector()687 hypertext_inspector::hypertext_inspector()
688 {
689 register_signature( ".htm" );
690 register_signature( ".html" );
691 register_signature( ".shtml" );
692 }
693
694 // impute_library ----------------------------------------------------------//
695
696 // may return an empty string [gps]
impute_library(const path & full_dir_path)697 string impute_library( const path & full_dir_path )
698 {
699 path relative( relative_to( full_dir_path, search_root_path() ) );
700 if ( relative.empty() ) return "boost-root";
701 string first( (*relative.begin()).string() );
702 string second = // borland 5.61 requires op=
703 ++relative.begin() == relative.end()
704 ? string() : (*++relative.begin()).string();
705
706 if ( first == "boost" )
707 return second;
708
709 return (( first == "libs" || first == "tools" ) && !second.empty())
710 ? second : first;
711 }
712
713 } // namespace inspect
714 } // namespace boost
715
716 // cpp_main() --------------------------------------------------------------//
717
718 #if !INSPECT_USE_BOOST_TEST
main(int argc_param,char * argv_param[])719 int main( int argc_param, char * argv_param[] )
720 #else
721 int cpp_main( int argc_param, char * argv_param[] )
722 #endif
723 {
724 // <hack> for the moment, let's be on the safe side
725 // and ensure we don't modify anything being pointed to;
726 // then we'll do some cleanup here
727 int argc = argc_param;
728 const char* const * argv = &argv_param[0];
729
730 if ( argc > 1 && (std::strcmp( argv[1], "-help" ) == 0
731 || std::strcmp( argv[1], "--help" ) == 0 ) )
732 {
733 std::clog << "Usage: inspect [search-root] [options...]\n\n"
734 " search-root default is the current directory (i.e. '.')\n\n"
735 << options() << '\n';
736 return 0;
737 }
738
739 bool options_not_set = true;
740 bool license_ck = false;
741 bool copyright_ck = false;
742 bool crlf_ck = false;
743 bool end_ck = false;
744 bool link_ck = false;
745 bool path_name_ck = false;
746 bool tab_ck = false;
747 bool ascii_ck = false;
748 bool apple_ck = false;
749 bool assert_ck = false;
750 bool deprecated_ck = false;
751 bool minmax_ck = false;
752 bool unnamed_ck = false;
753 const char* version_string = 0;
754
755 if ( argc > 1 && *argv[1] != '-' )
756 {
757 search_root = fs::canonical(fs::absolute(argv[1], fs::initial_path()));
758 --argc; ++argv;
759 }
760
761 bool invalid_options = false;
762 for(; argc > 1; --argc, ++argv )
763 {
764 if ( std::strcmp( argv[1], "-license" ) == 0 ) {
765 options_not_set = false;
766 license_ck = true;
767 }
768 else if ( std::strcmp( argv[1], "-copyright" ) == 0 ) {
769 options_not_set = false;
770 copyright_ck = true;
771 }
772 else if ( std::strcmp( argv[1], "-crlf" ) == 0 ) {
773 options_not_set = false;
774 crlf_ck = true;
775 }
776 else if ( std::strcmp( argv[1], "-end" ) == 0 ) {
777 options_not_set = false;
778 end_ck = true;
779 }
780 else if ( std::strcmp( argv[1], "-link" ) == 0 ) {
781 options_not_set = false;
782 link_ck = true;
783 }
784 else if ( std::strcmp( argv[1], "-path_name" ) == 0 ) {
785 options_not_set = false;
786 path_name_ck = true;
787 }
788 else if ( std::strcmp( argv[1], "-tab" ) == 0 ) {
789 options_not_set = false;
790 tab_ck = true;
791 }
792 else if ( std::strcmp( argv[1], "-ascii" ) == 0 ) {
793 options_not_set = false;
794 ascii_ck = true;
795 }
796 else if ( std::strcmp( argv[1], "-apple_macro" ) == 0 ) {
797 options_not_set = false;
798 apple_ck = true;
799 }
800 else if ( std::strcmp( argv[1], "-assert_macro" ) == 0 ) {
801 options_not_set = false;
802 assert_ck = true;
803 }
804 else if ( std::strcmp( argv[1], "-deprecated_macro" ) == 0 ) {
805 options_not_set = false;
806 deprecated_ck = true;
807 }
808 else if ( std::strcmp( argv[1], "-minmax" ) == 0 ) {
809 options_not_set = false;
810 minmax_ck = true;
811 }
812 else if ( std::strcmp( argv[1], "-unnamed" ) == 0 ) {
813 options_not_set = false;
814 unnamed_ck = true;
815 }
816 else if ( argc > 1 && std::strcmp( argv[1], "-text" ) == 0 )
817 {
818 display_format = display_text;
819 }
820 else if ( argc > 1 && std::strcmp( argv[1], "-brief" ) == 0 )
821 {
822 display_mode = display_brief;
823 }
824 else if ( std::strcmp( argv[1], "-version-string" ) == 0 ) {
825 if (argc == 2 || argv[2][0] == '-') {
826 std::cerr << "Missing value for -version-string.\n";
827 invalid_options = true;
828 }
829 else {
830 --argc, ++argv;
831 version_string = argv[1];
832 }
833 }
834 else
835 {
836 std::cerr << "unknown option: " << argv[1] << '\n';
837 invalid_options = true;
838 }
839 }
840 if ( invalid_options ) {
841 std::cerr << "\nvalid options are:\n"
842 << options();
843 return 1;
844 }
845
846 if (options_not_set) {
847 license_ck = true;
848 copyright_ck = true;
849 crlf_ck = true;
850 end_ck = true;
851 link_ck = true;
852 path_name_ck = true;
853 tab_ck = true;
854 ascii_ck = true;
855 apple_ck = true;
856 assert_ck = true;
857 deprecated_ck = true;
858 minmax_ck = true;
859 unnamed_ck = true;
860 }
861
862 string inspector_keys;
863
864 { // begin reporting block
865
866 // since this is in its own block; reporting will happen
867 // automatically, from each registered inspector, when
868 // leaving, due to destruction of the inspector_list object
869 inspector_list inspectors;
870
871 if ( license_ck )
872 inspectors.push_back( inspector_element( new boost::inspect::license_check ) );
873 if ( copyright_ck )
874 inspectors.push_back( inspector_element( new boost::inspect::copyright_check ) );
875 if ( crlf_ck )
876 inspectors.push_back( inspector_element( new boost::inspect::crlf_check ) );
877 if ( end_ck )
878 inspectors.push_back( inspector_element( new boost::inspect::end_check ) );
879 if ( link_ck )
880 inspectors.push_back( inspector_element( new boost::inspect::link_check ) );
881 if ( path_name_ck )
882 inspectors.push_back( inspector_element( new boost::inspect::file_name_check ) );
883 if ( tab_ck )
884 inspectors.push_back( inspector_element( new boost::inspect::tab_check ) );
885 if ( ascii_ck )
886 inspectors.push_back( inspector_element( new boost::inspect::ascii_check ) );
887 if ( apple_ck )
888 inspectors.push_back( inspector_element( new boost::inspect::apple_macro_check ) );
889 if ( assert_ck )
890 inspectors.push_back( inspector_element( new boost::inspect::assert_macro_check ) );
891 if ( deprecated_ck )
892 inspectors.push_back( inspector_element( new boost::inspect::deprecated_macro_check ) );
893 if ( minmax_ck )
894 inspectors.push_back( inspector_element( new boost::inspect::minmax_check ) );
895 if ( unnamed_ck )
896 inspectors.push_back( inspector_element( new boost::inspect::unnamed_namespace_check ) );
897
898 visit_all<fs::directory_iterator>( search_root.leaf().string(),
899 search_root, inspectors );
900
901 // close
902 for ( inspector_list::iterator itr = inspectors.begin();
903 itr != inspectors.end(); ++itr )
904 {
905 itr->inspector->close();
906 }
907
908 string run_date ( "n/a" );
909 boost::time_string( run_date );
910
911 if (display_format == display_text)
912 {
913 std::cout
914 <<
915 "Boost Inspection Report\n"
916 "Run Date: " << run_date << "\n"
917 "\n"
918 ;
919
920 if (version_string) {
921 std::cout
922 << "The files checked were from "
923 << version_string
924 << ".\n\n";
925 }
926
927 std::cout
928 << "Totals:\n"
929 << " " << file_count << " files scanned\n"
930 << " " << directory_count << " directories scanned (including root)\n"
931 << " " << error_count << " problems reported\n"
932 << '\n'
933 ;
934 }
935 else
936 {
937 //
938 std::cout << doctype_declaration() << '\n';
939
940 std::cout
941 << "<html>\n"
942 "<head>\n"
943 "<style> body { font-family: sans-serif; } </style>\n"
944 "<title>Boost Inspection Report</title>\n"
945 "</head>\n"
946
947 "<body>\n"
948 // we should not use a table, of course [gps]
949 "<table>\n"
950 "<tr>\n"
951 "<td><img src=\"http://www.boost.org/boost.png\" alt=\"Boost logo\" />"
952 "</td>\n"
953 "<td>\n"
954 "<h1>Boost Inspection Report</h1>\n"
955 "<b>Run Date:</b> " << run_date << "\n"
956 //" / " << validator_link( "validate me" ) << " /\n"
957 "</td>\n"
958 "</tr>\n"
959 "</table>\n"
960
961 "<p>This report is generated by an <a href=\"http://www.boost.org/tools/inspect/index.html\">inspection\n"
962 "program</a> that checks files for the problems noted below.</p>\n"
963 ;
964 if (version_string) {
965 std::cout
966 << "<p>The files checked were from "
967 << html_encode(version_string)
968 << ".</p>\n";
969 }
970
971
972 std::cout
973 << "<h2>Totals</h2>\n"
974 << file_count << " files scanned<br>\n"
975 << directory_count << " directories scanned (including root)<br>\n"
976 << error_count << " problems reported\n<p>";
977 }
978
979 for ( inspector_list::iterator itr = inspectors.begin();
980 itr != inspectors.end(); ++itr )
981 {
982
983 inspector_keys += static_cast<string>(" ")
984 + itr->inspector->name()
985 + ' ' + itr->inspector->desc()
986 + line_break()
987 ;
988 }
989
990 if (display_format == display_text)
991 std::cout << "\nProblem counts:\n";
992 else
993 std::cout << "\n<h2>Problem counts</h2>\n<blockquote><p>\n" ;
994
995 } // end of block: starts reporting
996
997 if (display_format == display_text)
998 std::cout << "\n" ;
999 else
1000 std::cout << "</blockquote>\n";
1001
1002 std::sort( msgs.begin(), msgs.end() );
1003
1004 worst_offenders_count();
1005 std::stable_sort( libs.begin(), libs.end() );
1006
1007 if ( !libs.empty() && display_mode != display_brief)
1008 display_worst_offenders();
1009
1010 if ( !msgs.empty() )
1011 {
1012 display_summary();
1013
1014 if (display_format == display_text)
1015 {
1016 std::cout << "Details:\n" << inspector_keys;
1017 std::cout << "\nDirectories with a file named \"" << boost_no_inspect << "\" will not be inspected.\n"
1018 "Files containing \"" << boost_no_inspect << "\" will not be inspected.\n";
1019 }
1020 else
1021 {
1022 std::cout << "<h2>Details</h2>\n" << inspector_keys;
1023 std::cout << "\n<p>Directories with a file named \"" << boost_no_inspect << "\" will not be inspected.<br>\n"
1024 "Files containing \"" << boost_no_inspect << "\" will not be inspected.</p>\n";
1025 }
1026 display_details();
1027 }
1028
1029 if (display_format == display_text)
1030 {
1031 std::cout << "\n\n" ;
1032 }
1033 else
1034 {
1035 std::cout
1036 << "</body>\n"
1037 "</html>\n";
1038 }
1039
1040 return error_count ? 1 : 0;
1041 }
1042