Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/tools/inspect/inspect.cpp @ 35

Last change on this file since 35 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 21.1 KB
Line 
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
19#include <vector>
20#include <list>
21#include <algorithm>
22#include <cstring>
23
24#include "boost/shared_ptr.hpp"
25#include "boost/filesystem/operations.hpp"
26#include "boost/filesystem/fstream.hpp"
27
28#include "time_string.hpp"
29
30#include "inspector.hpp"
31
32// the inspectors
33#include "copyright_check.hpp"
34#include "crlf_check.hpp"
35#include "license_check.hpp"
36#include "link_check.hpp"
37#include "long_name_check.hpp"
38#include "tab_check.hpp"
39#include "minmax_check.hpp"
40#include "unnamed_namespace_check.hpp"
41
42#include "cvs_iterator.hpp"
43
44#include "boost/test/included/prg_exec_monitor.hpp"
45
46namespace fs = boost::filesystem;
47
48namespace
49{
50  class inspector_element
51  {
52    typedef boost::shared_ptr< boost::inspect::inspector > inspector_ptr;
53
54  public:
55    inspector_ptr  inspector;
56    explicit
57    inspector_element( boost::inspect::inspector * p ) : inspector(p) {}
58  };
59
60  typedef std::list< inspector_element > inspector_list;
61
62  long file_count = 0;
63  long directory_count = 0;
64  long error_count = 0;
65
66  boost::inspect::string_set content_signatures;
67
68  struct error_msg
69  {
70    string library;
71    string rel_path;
72    string msg;
73
74    bool operator<( const error_msg & rhs ) const
75    {
76      if ( library < rhs.library ) return true;
77      if ( library > rhs.library ) return false;
78      if ( rel_path < rhs.rel_path ) return true;
79      if ( rel_path > rhs.rel_path ) return false;
80      return msg < rhs.msg;
81    }
82  };
83
84  typedef std::vector< error_msg > error_msg_vector;
85  error_msg_vector msgs;
86
87//  visit_predicate (determines which directories are visited)  --------------//
88
89  typedef bool(*pred_type)(const path&);
90
91  bool visit_predicate( const path & pth )
92  {
93    string local( boost::inspect::relative_to( pth, fs::initial_path() ) );
94    string leaf( pth.leaf() );
95    return
96      // so we can inspect a checkout
97      leaf != "CVS"
98      // don't look at binaries
99      && leaf != "bin"
100      && leaf != "bin.v2"
101      // this really out of our hands
102      && leaf != "jam_src"
103      && local.find("tools/jam/src") != 0
104      // too many issues with generated HTML files
105      && leaf != "status"
106      // no point in checking doxygen xml output
107      && local.find("doc/xml") != 0
108      // ignore some web files
109      && leaf != ".htaccess"
110      ;
111  }
112
113//  library_from_content  ----------------------------------------------------//
114
115  string library_from_content( const string & content )
116  {
117    const string unknown_library ( "unknown" );
118    const string lib_root ( "www.boost.org/libs/" );
119    string::size_type pos( content.find( lib_root ) );
120
121    string lib = unknown_library;
122
123    if ( pos != string::npos ) {
124
125        pos += lib_root.length();
126
127        const char delims[] = " " // space and...
128                              "/\n\r\t";
129
130        string::size_type n = content.find_first_of( string(delims), pos );
131        if (n != string::npos)
132            lib = string(content, pos, n - pos);
133       
134    }
135
136    return lib;
137  }
138
139//  find_signature  ----------------------------------------------------------//
140
141  bool find_signature( const path & file_path,
142    const boost::inspect::string_set & signatures )
143  {
144    string name( file_path.leaf() );
145    if ( signatures.find( name ) == signatures.end() )
146    {
147      string::size_type pos( name.rfind( '.' ) );
148      if ( pos == string::npos
149        || signatures.find( name.substr( pos ) )
150          == signatures.end() ) return false;
151    }
152    return true;
153  }
154
155//  load_content  ------------------------------------------------------------//
156
157  void load_content( const path & file_path, string & target )
158  {
159    target = "";
160
161    if ( !find_signature( file_path, content_signatures ) ) return;
162
163    fs::ifstream fin( file_path, std::ios_base::in|std::ios_base::binary );
164    if ( !fin )
165      throw string( "could not open input file: " ) + file_path.string();
166    std::getline( fin, target, '\0' ); // read the whole file
167  }
168
169//  check  -------------------------------------------------------------------//
170
171  void check( const string & lib,
172    const path & pth, const string & content, const inspector_list & insp_list )
173  {
174    // invoke each inspector
175    for ( inspector_list::const_iterator itr = insp_list.begin();
176      itr != insp_list.end(); ++itr )
177    {
178      itr->inspector->inspect( lib, pth ); // always call two-argument form
179      if ( find_signature( pth, itr->inspector->signatures() ) )
180      {
181          itr->inspector->inspect( lib, pth, content );
182      }
183    }
184  }
185
186//  visit_all  ---------------------------------------------------------------//
187
188  template< class DirectoryIterator >
189  void visit_all( const string & lib,
190    const path & dir_path, const inspector_list & insps )
191  {
192    static DirectoryIterator end_itr;
193    ++directory_count;
194
195    for ( DirectoryIterator itr( dir_path ); itr != end_itr; ++itr )
196    {
197
198      if ( fs::is_directory( *itr ) )
199      {
200        if ( visit_predicate( *itr ) )
201        {
202          string cur_lib( boost::inspect::impute_library( *itr ) );
203          check( cur_lib, *itr, "", insps );
204          visit_all<DirectoryIterator>( cur_lib, *itr, insps );
205        }
206      }
207      else
208      {
209        ++file_count;
210        string content;
211        load_content( *itr, content );
212        check( lib.empty()
213                ? library_from_content( content ) : lib
214               , *itr, content, insps );
215      }
216    }
217  }
218
219//  display  -----------------------------------------------------------------//
220
221  enum display_format_type
222  {
223    display_html, display_text
224  }
225  display_format = display_html;
226
227  enum display_mode_type
228  {
229    display_full, display_brief
230  }
231  display_mode = display_full;
232
233//  display_summary_helper  --------------------------------------------------//
234
235  void display_summary_helper( const string & current_library, int err_count )
236  {
237    if (display_text == display_format)
238    {
239        std::cout << "  " << current_library << " (" << err_count << ")\n";
240    }
241    else
242    {
243      std::cout
244        << "  <tr><td><a href=\"#"
245        << current_library          // what about malformed for URI refs? [gps]
246        << "\">" << current_library
247        << "</a></td><td align=\"center\">"
248        << err_count << "</td></tr>\n";
249    }
250  }
251
252//  display_summary  ---------------------------------------------------------//
253
254  void display_summary()
255  {
256    if (display_text == display_format)
257    {
258      std::cout << "Summary:\n";
259    }
260    else
261    {
262      std::cout
263        << "</pre>\n"
264        "<h2>Summary</h2>\n"
265        "<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\">\n"
266        "  <tr>\n"
267        "    <td><b>Library</b></td>\n"
268        "    <td><b>Problems</b></td>\n"
269        "  </tr>\n"
270        ;
271    }
272
273    string current_library( msgs.begin()->library );
274    int err_count = 0;
275    for ( error_msg_vector::iterator itr ( msgs.begin() );
276      itr != msgs.end(); ++itr )
277    {
278      if ( current_library != itr->library )
279      {
280        display_summary_helper( current_library, err_count );
281        current_library = itr->library;
282        err_count = 0;
283      }
284      ++err_count;
285    }
286    display_summary_helper( current_library, err_count );
287
288    if (display_text == display_format)
289    {
290      std::cout << "\n";
291    }
292    else
293    {
294      std::cout << "</table>\n";
295    }
296  }
297
298
299//  display_details  ---------------------------------------------------------//
300
301  void display_details()
302  {
303    // gps - review this
304
305    if (display_text == display_format)
306    {
307      // display error messages with group indication
308      error_msg current;
309      string sep;
310      for ( error_msg_vector::iterator itr ( msgs.begin() );
311        itr != msgs.end(); ++itr )
312      {
313        if ( current.library != itr->library )
314        {
315          if ( display_full == display_mode )
316              std::cout << "\n|" << itr->library << "|\n";
317          else
318              std::cout << "\n\n|" << itr->library << '|';
319        }
320
321        if ( current.library != itr->library
322          || current.rel_path != itr->rel_path )
323        {
324          if ( display_full == display_mode )
325          {
326            std::cout << "  " << itr->rel_path << ":\n";
327          }
328          else
329          {
330            path current_rel_path(current.rel_path);
331            path this_rel_path(itr->rel_path);
332            if (current_rel_path.branch_path() != this_rel_path.branch_path())
333            {
334              std::cout << "\n  " << this_rel_path.branch_path().string() << '/';
335            }
336            std::cout << "\n    " << this_rel_path.leaf() << ':';
337          }
338        }
339        if ( current.library != itr->library
340          || current.rel_path != itr->rel_path
341          || current.msg != itr->msg )
342        {
343          const string m = itr->msg;
344
345          if ( display_full == display_mode )
346              std::cout << "    " << m << '\n';
347          else
348              std::cout << ' ' << m;
349        }
350        current.library = itr->library;
351        current.rel_path = itr->rel_path;
352        current.msg = itr->msg;
353      }
354      std::cout << "\n";
355    }
356    else
357    {
358      // display error messages with group indication
359      error_msg current;
360      string sep;
361      bool first = true;
362      for ( error_msg_vector::iterator itr ( msgs.begin() );
363        itr != msgs.end(); ++itr )
364      {
365        if ( current.library != itr->library )
366        {
367          if ( !first ) std::cout << "</pre>\n";
368          std::cout << "\n<h3><a name=\"" << itr->library
369                    << "\">" << itr->library << "</a></h3>\n<pre>";
370        }
371        if ( current.library != itr->library
372          || current.rel_path != itr->rel_path )
373        {
374          std::cout << "\n";
375          std::cout << itr->rel_path;
376          sep = ": ";
377        }
378        if ( current.library != itr->library
379          || current.rel_path != itr->rel_path
380          || current.msg != itr->msg )
381        {
382          std::cout << sep << itr->msg;
383          sep = ", ";
384        }
385        current.library = itr->library;
386        current.rel_path = itr->rel_path;
387        current.msg = itr->msg;
388        first = false;
389      }
390      std::cout << "</pre>\n";
391    }
392  }
393
394  const char * options()
395  {
396    return
397         "  -license\n"
398         "  -copyright\n"
399         "  -crlf\n"
400         "  -link\n"
401         "  -long_name\n"
402         "  -tab\n"
403         "  -minmax\n"
404         "  -unnamed\n"
405         " default is all checks on; otherwise options specify desired checks"
406         "\n";
407  }
408
409  const char * doctype_declaration()
410  {
411    return
412         "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
413         "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"
414         ;
415  }
416
417  std::string validator_link(const std::string & text)
418  {
419    return
420        // with link to validation service
421        "<a href=\"http://validator.w3.org/check?uri=referer\">"
422        + text
423        + "</a>"
424        ;
425  }
426
427} // unnamed namespace
428
429namespace boost
430{
431  namespace inspect
432  {
433
434//  register_signature  ------------------------------------------------------//
435
436    void inspector::register_signature( const string & signature )
437    {
438      m_signatures.insert( signature );
439      content_signatures.insert( signature );
440    }
441
442//  error  -------------------------------------------------------------------//
443
444    void inspector::error( const string & library_name,
445      const path & full_path, const string & msg )
446    {
447      ++error_count;
448      error_msg err_msg;
449      err_msg.library = library_name;
450      err_msg.rel_path = relative_to( full_path, fs::initial_path() );
451      err_msg.msg = msg;
452      msgs.push_back( err_msg );
453
454//     std::cout << library_name << ": "
455//        << full_path.string() << ": "
456//        << msg << '\n';
457
458    }
459
460    source_inspector::source_inspector()
461    {
462      // C/C++ source code...
463      register_signature( ".c" );
464      register_signature( ".cpp" );
465      register_signature( ".css" );
466      register_signature( ".cxx" );
467      register_signature( ".h" );
468      register_signature( ".hpp" );
469      register_signature( ".hxx" );
470      register_signature( ".inc" );
471      register_signature( ".ipp" );
472
473      // Boost.Build BJam source code...
474      register_signature( "Jamfile" );
475      register_signature( ".jam" );
476      register_signature( ".v2" );
477
478      // Other scripts; Python, shell, autoconfig, etc.
479      register_signature( "configure.in" );
480      register_signature( "GNUmakefile" );
481      register_signature( "Makefile" );
482      register_signature( ".bat" );
483      register_signature( ".mak" );
484      register_signature( ".pl" );
485      register_signature( ".py" );
486      register_signature( ".sh" );
487
488      // Hypertext, Boost.Book, and other text...
489      register_signature( "news" );
490      register_signature( "readme" );
491      register_signature( "todo" );
492      register_signature( "NEWS" );
493      register_signature( "README" );
494      register_signature( "TODO" );
495      register_signature( ".boostbook" );
496      register_signature( ".htm" );
497      register_signature( ".html" );
498      register_signature( ".rst" );
499      register_signature( ".sgml" );
500      register_signature( ".shtml" );
501      register_signature( ".txt" );
502      register_signature( ".xml" );
503      register_signature( ".xsd" );
504      register_signature( ".xsl" );
505    }
506
507    hypertext_inspector::hypertext_inspector()
508    {
509      register_signature( ".htm" );
510      register_signature( ".html" );
511      register_signature( ".shtml" );
512    }
513
514//  impute_library  ----------------------------------------------------------//
515
516    // may return an empty string [gps]
517    string impute_library( const path & full_dir_path )
518    {
519      path relative( relative_to( full_dir_path, fs::initial_path() ),
520        fs::no_check );
521      if ( relative.empty() ) return "boost-root";
522      string first( *relative.begin() );
523      string second =  // borland 5.61 requires op=
524        ++relative.begin() == relative.end()
525          ? string() : *++relative.begin();
526
527      if ( first == "boost" )
528        return second;
529
530      return (( first == "libs" || first == "tools" ) && !second.empty())
531        ? second : first;
532    }
533
534  } // namespace inspect
535} // namespace boost
536
537//  cpp_main()  --------------------------------------------------------------//
538
539int cpp_main( int argc_param, char * argv_param[] )
540{
541  // <hack> for the moment, let's be on the safe side
542  // and ensure we don't modify anything being pointed to;
543  // then we'll do some cleanup here
544  int argc = argc_param;
545  const char* const * argv = &argv_param[0];
546
547  if ( argc > 1 && (std::strcmp( argv[1], "-help" ) == 0
548    || std::strcmp( argv[1], "--help" ) == 0 ) )
549  {
550    std::clog << "Usage: inspect [-cvs] [-text] [-brief] [options...]\n\n"
551      " Options:\n"
552      << options() << '\n';
553    return 0;
554  }
555
556  bool license_ck = true;
557  bool copyright_ck = true;
558  bool crlf_ck = true;
559  bool link_ck = true;
560  bool long_name_ck = true;
561  bool tab_ck = true;
562  bool minmax_ck = true;
563  bool unnamed_ck = true;
564  bool cvs = false;
565
566  if ( argc > 1 && std::strcmp( argv[1], "-cvs" ) == 0 )
567  {
568    cvs = true;
569    --argc; ++argv;
570  }
571
572  if ( argc > 1 && std::strcmp( argv[1], "-text" ) == 0 )
573  {
574    display_format = display_text;
575    --argc; ++argv;
576  }
577
578  if ( argc > 1 && std::strcmp( argv[1], "-brief" ) == 0 )
579  {
580    display_mode = display_brief;
581    --argc; ++argv;
582  }
583
584  if ( argc > 1 && *argv[1] == '-' )
585  {
586    license_ck = false;
587    copyright_ck = false;
588    crlf_ck = false;
589    link_ck = false;
590    long_name_ck = false;
591    tab_ck = false;
592    minmax_ck = false;
593    unnamed_ck = false;
594  }
595
596  bool invalid_options = false;
597  for(; argc > 1; --argc, ++argv )
598  {
599    if ( std::strcmp( argv[1], "-license" ) == 0 )
600      license_ck = true;
601    else if ( std::strcmp( argv[1], "-copyright" ) == 0 )
602      copyright_ck = true;
603    else if ( std::strcmp( argv[1], "-crlf" ) == 0 )
604        crlf_ck = true;
605    else if ( std::strcmp( argv[1], "-link" ) == 0 )
606      link_ck = true;
607    else if ( std::strcmp( argv[1], "-long_name" ) == 0 )
608      long_name_ck = true;
609    else if ( std::strcmp( argv[1], "-tab" ) == 0 )
610      tab_ck = true;
611    else if ( std::strcmp( argv[1], "-minmax" ) == 0 )
612        minmax_ck = true;
613    else if ( std::strcmp( argv[1], "-unnamed" ) == 0 )
614        unnamed_ck = true;
615    else
616    {
617      std::cerr << "unknown option: " << argv[1] << '\n';
618      invalid_options = true;
619    }
620  }
621  if ( invalid_options ) {
622      std::cerr << "\nvalid options are:\n"
623                << options();
624      return 1;
625  }
626
627  string inspector_keys;
628  fs::initial_path();
629
630  {
631
632  // note how this is in its own block; reporting will happen
633  // automatically, from each registered inspector, when
634  // leaving, due to destruction of the inspector_list object
635  inspector_list inspectors;
636
637  if ( license_ck )
638    inspectors.push_back( inspector_element( new boost::inspect::license_check ) );
639  if ( copyright_ck )
640    inspectors.push_back( inspector_element( new boost::inspect::copyright_check ) );
641  if ( crlf_ck )
642    inspectors.push_back( inspector_element( new boost::inspect::crlf_check ) );
643  if ( link_ck )
644    inspectors.push_back( inspector_element( new boost::inspect::link_check ) );
645  if ( long_name_ck )
646    inspectors.push_back( inspector_element( new boost::inspect::file_name_check ) );
647  if ( tab_ck )
648      inspectors.push_back( inspector_element( new boost::inspect::tab_check ) );
649  if ( minmax_ck )
650      inspectors.push_back( inspector_element( new boost::inspect::minmax_check ) );
651  if ( unnamed_ck )
652      inspectors.push_back( inspector_element( new boost::inspect::unnamed_namespace_check ) );
653
654  // perform the actual inspection, using the requested type of iteration
655  if ( cvs )
656    visit_all<hack::cvs_iterator>( "boost-root",
657      fs::initial_path(), inspectors );
658  else
659    visit_all<fs::directory_iterator>( "boost-root",
660      fs::initial_path(), inspectors );
661
662  // close
663  for ( inspector_list::iterator itr = inspectors.begin();
664        itr != inspectors.end(); ++itr )
665  {
666    itr->inspector->close();
667  }
668
669  string run_date ( "n/a" );
670  boost::time_string( run_date );
671
672  if (display_text == display_format)
673  {
674    std::cout
675      <<
676        "Boost Inspection Report\n"
677        "Run Date: " << run_date  << "\n"
678        "\n"
679        "An inspection program <http://www.boost.org/tools/inspect/index.html>\n"
680        "checks each file in the current Boost CVS for various problems,\n"
681        "generating this as output. Problems detected include tabs in files,\n"
682        "missing copyrights, broken URL's, and similar misdemeanors.\n"
683        "\n"
684      ;
685
686    std::cout
687      << "Totals:\n"
688      << "  " << file_count << " files scanned\n"
689      << "  " << directory_count << " directories scanned (including root)\n"
690      << "  " << error_count << " problems reported\n"
691      << '\n'
692      ;
693  }
694  else
695  {
696    //
697    std::cout << doctype_declaration() << '\n';
698
699    std::cout
700      << "<html>\n"
701      "<head>\n"
702      "<title>Boost Inspection Report</title>\n"
703      "</head>\n"
704
705      "<body>\n"
706      // we should not use a table, of course [gps]
707      "<table>\n"
708      "<tr>\n"
709      "<td><img src=\"../boost.png\" alt=\"Boost logo\" />"
710      "</td>\n"
711      "<td>\n"
712      "<h1>Boost Inspection Report</h1>\n"
713      "<b>Run Date:</b> " << run_date  << "\n"
714      "&nbsp;&nbsp;/ " << validator_link( "validate me" ) << " /\n"
715      "</td>\n"
716      "</tr>\n"
717      "</table>\n"
718
719      "<p>An <a href=\"http://www.boost.org/tools/inspect/index.html\">inspection\n"
720      "program</a> checks each file in the current Boost CVS for various problems,\n"
721      "generating this web page as output. Problems detected include tabs in files,\n"
722      "missing copyrights, broken URL's, and similar misdemeanors.</p>\n"
723      ;
724
725    std::cout
726      << "<h2>Totals</h2>\n<pre>"
727      << file_count << " files scanned\n"
728      << directory_count << " directories scanned (including root)\n"
729      << error_count << " problems reported\n";
730  }
731
732  for ( inspector_list::iterator itr = inspectors.begin();
733        itr != inspectors.end(); ++itr )
734  {
735    const string line_break (
736        display_text == display_format? "\n" : "<br />\n"); // gps
737
738    inspector_keys += static_cast<string>("  ")
739        + itr->inspector->name()
740        + ' ' + itr->inspector->desc()
741        + line_break
742        ;
743  }
744
745 
746  std::cout
747      << "\nProblem counts:\n";
748
749  } // end of block: starts reporting
750
751  if (display_text == display_format)
752  {
753    std::cout << "\n" ;
754  }
755
756  std::sort( msgs.begin(), msgs.end() );
757
758  if ( !msgs.empty() )
759  {
760    display_summary();
761
762    if (display_text == display_format)
763    {
764      std::cout << "Details:\n" << inspector_keys;
765    }
766    else
767    {
768      std::cout << "<h2>Details</h2>\n" << inspector_keys;
769    }
770    display_details();
771  }
772
773  if (display_text == display_format)
774  {
775    std::cout << "\n\n" ;
776  }
777  else
778  {
779    std::cout
780      << "</body>\n"
781      "</html>\n";
782  }
783
784  return 0;
785}
Note: See TracBrowser for help on using the repository browser.