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