View Javadoc

1   /**
2    * Redistribution  and use  in source  and binary  forms, with  or without
3    * modification, are permitted provided  that the following conditions are
4    * met :
5    *
6    * . Redistributions  of  source  code  must  retain  the  above copyright
7    *   notice, this list of conditions and the following disclaimer.
8    *
9    * . Redistributions in  binary form  must reproduce  the above  copyright
10   *   notice, this list of conditions  and the following disclaimer in  the
11   *   documentation and/or other materials provided with the distribution.
12   *
13   * . The name of the author may not be used to endorse or promote products
14   *   derived from this software without specific prior written permission.
15   *
16   * THIS SOFTWARE IS  PROVIDED BY THE  AUTHOR ``AS IS''  AND ANY EXPRESS  OR
17   * IMPLIED  WARRANTIES,  INCLUDING,  BUT   NOT  LIMITED  TO,  THE   IMPLIED
18   * WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE ARE
19   * DISCLAIMED.  IN NO  EVENT SHALL  THE AUTHOR  BE LIABLE  FOR ANY  DIRECT,
20   * INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL  DAMAGES
21   * (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT OF  SUBSTITUTE  GOODS OR
22   * SERVICES;  LOSS  OF USE,  DATA,  OR PROFITS;  OR  BUSINESS INTERRUPTION)
23   * HOWEVER CAUSED  AND ON  ANY THEORY  OF LIABILITY,  WHETHER IN  CONTRACT,
24   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25   * ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE, EVEN  IF  ADVISED OF  THE
26   * POSSIBILITY OF SUCH DAMAGE.
27   */
28  
29  package cppncss;
30  
31  import java.io.FileNotFoundException;
32  import java.io.FileOutputStream;
33  import java.io.PrintStream;
34  import java.util.ArrayList;
35  import java.util.List;
36  import cppast.VisitorComposite;
37  import cppncss.counter.CcnCounter;
38  import cppncss.counter.Counter;
39  import cppncss.counter.FileVisitor;
40  import cppncss.counter.FunctionCounter;
41  import cppncss.counter.FunctionVisitor;
42  import cppncss.counter.NcssCounter;
43  import cppncss.measure.AverageCollector;
44  import cppncss.measure.Collector;
45  import cppncss.measure.MeasureCollector;
46  import cppncss.measure.SumCollector;
47  import cpptools.Analyzer;
48  import cpptools.ConsoleLogger;
49  import cpptools.EventHandler;
50  import cpptools.FileObserverComposite;
51  import cpptools.Options;
52  import cpptools.Usage;
53  
54  /**
55   * Provides code measures for C++.
56   *
57   * @author Mathieu Champlon
58   */
59  public final class CppNcss
60  {
61      private final VisitorComposite visitors = new VisitorComposite();
62      private final FileObserverComposite observers = new FileObserverComposite();
63      private final List<Collector> collectors = new ArrayList<Collector>();
64      private final ResultOutput output;
65      private final Analyzer analyzer;
66  
67      /**
68       * Implements a factory to create visitors from a given counter.
69       *
70       * @author Mathieu Champlon
71       */
72      private interface VisitorFactory
73      {
74          void register( Counter counter );
75      }
76  
77      private final VisitorFactory functionVisitorFactory = new VisitorFactory()
78      {
79          public void register( final Counter counter )
80          {
81              visitors.register( new FunctionVisitor( counter ) );
82          }
83      };
84      private final VisitorFactory fileVisitorFactory = new VisitorFactory()
85      {
86          public void register( final Counter counter )
87          {
88              final FileVisitor visitor = new FileVisitor( counter );
89              observers.register( visitor );
90              visitors.register( visitor );
91          }
92      };
93  
94      /**
95       * Create a CppNcss instance.
96       *
97       * @param options the options
98       * @param handler the log handler
99       * @throws FileNotFoundException when the log file fails
100      */
101     public CppNcss( final Options options, final EventHandler handler ) throws FileNotFoundException
102     {
103         output = createOutput( options );
104         analyzer = new Analyzer( options, visitors, observers, handler );
105         register( options, new MeasureCollector( options, new ResultOutputAdapter( "Function", output ) ), functionVisitorFactory );
106         register( options, new AverageCollector( new ResultOutputAdapter( "Function", output ) ), functionVisitorFactory );
107         register( options, new MeasureCollector( options, new ResultOutputAdapter( "File", output ) ), fileVisitorFactory );
108         register( options, new AverageCollector( new ResultOutputAdapter( "File", output ) ), fileVisitorFactory );
109         register( options, new SumCollector( new ResultOutputAdapter( "Project", output ) ), fileVisitorFactory );
110     }
111 
112     private void register( final Options options, final Collector collector, final VisitorFactory factory )
113     {
114         collectors.add( collector );
115         observers.register( collector );
116         for( String counter : filter( options ) )
117             factory.register( create( collector, counter ) );
118     }
119 
120     private List<String> filter( final Options options )
121     {
122         final List<String> counters = new ArrayList<String>();
123         for( String value : extract( options ).split( "," ) )
124             if( !counters.contains( value ) )
125                 counters.add( value );
126         return counters;
127     }
128 
129     private String extract( final Options options )
130     {
131         final List<String> values = options.getOptionPropertyValues( "m" );
132         if( values.isEmpty() )
133             return "NCSS,CCN,function";
134         return values.get( 0 );
135     }
136 
137     private Counter create( final Collector collector, final String counter )
138     {
139         if( counter.equals( "NCSS" ) )
140             return new NcssCounter( collector );
141         if( counter.equals( "CCN" ) )
142             return new CcnCounter( collector );
143         if( counter.equals( "function" ) )
144             return new FunctionCounter( collector );
145         throw new IllegalArgumentException( "invalid measurement '" + counter + "'" );
146     }
147 
148     /**
149      * Run the analyzis.
150      */
151     public void run()
152     {
153         analyzer.run();
154         for( Collector collector : collectors )
155             collector.flush();
156         output.flush();
157     }
158 
159     private ResultOutput createOutput( final Options options ) throws FileNotFoundException
160     {
161         final PrintStream stream = createStream( options );
162         if( !options.hasOption( "x" ) )
163             return new AsciiResultOutput( stream );
164         return new XmlResultOutput( stream );
165     }
166 
167     private PrintStream createStream( final Options options ) throws FileNotFoundException
168     {
169         if( options.hasOption( "f" ) )
170             return new PrintStream( new FileOutputStream( options.getOptionPropertyValues( "f" ).get( 0 ) ) );
171         return System.out;
172     }
173 
174     /**
175      * Run the application.
176      *
177      * @param args the arguments
178      * @throws FileNotFoundException when the log file fails
179      */
180     public static void main( final String[] args ) throws FileNotFoundException
181     {
182         if( !check( args ) )
183             return;
184         final Options options = new Options( args );
185         new CppNcss( options, new ConsoleLogger( options ) ).run();
186     }
187 
188     private static boolean check( final String[] args )
189     {
190         if( args.length > 0 && !args[0].equals( "-h" ) )
191             return true;
192         usage();
193         return false;
194     }
195 
196     private static void usage()
197     {
198         final Usage usage = new Usage( "cppncss", "http://cppncss.sourceforge.net", "1.0.3" );
199         usage.addOption( "h", "print this message" );
200         usage.addOption( "d", "print debugging information" );
201         usage.addOption( "v", "be extra verbose" );
202         usage.addOption( "k", "keep going on parsing errors" );
203         usage.addOption( "r", "process directories recursively" );
204         usage.addOption( "x", "output result as xml" );
205         usage.addOption( "m=<measurements>", "output the <measurements> sorted in given order, default is equivalent to -m=NCSS,CCN,function" );
206         usage.addOption( "n=<number>", "output only the top <number> results" );
207         usage.addOption( "f=<file>", "output result to <file>" );
208         usage.addOption( "D<symbol>[=[<value>]]", "replace define <symbol> with <value>" );
209         usage.addOption( "M<symbol>[=[<value>]]", "replace macro <symbol> with <value>" );
210         usage.addOption( "p=<path>", "remove <path> prefix when displaying file names" );
211         usage.display();
212     }
213 }