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 }