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.File;
32  import java.io.FileNotFoundException;
33  import java.util.ArrayList;
34  import java.util.List;
35  import org.apache.tools.ant.BuildException;
36  import org.apache.tools.ant.DirectoryScanner;
37  import org.apache.tools.ant.taskdefs.AntlibDefinition;
38  import org.apache.tools.ant.types.FileSet;
39  import cpptools.AntLogger;
40  import cpptools.Options;
41  
42  /**
43   * Provides an Apache Ant task implementation for CppNcss.
44   *
45   * @author Mathieu Champlon
46   */
47  public final class CppNcssTask extends AntlibDefinition
48  {
49      private final List<FileSet> filesets = new ArrayList<FileSet>();
50      private final List<Argument> arguments = new ArrayList<Argument>();
51      private boolean keepGoing = false;
52      private String filename;
53      private String prefix;
54      private String measurements;
55      private int samples = -1;
56  
57      /**
58       * Add a set of source files.
59       *
60       * @param fileset a set of source files.
61       */
62      public void addFileset( final FileSet fileset )
63      {
64          filesets.add( fileset );
65      }
66  
67      /**
68       * Define a prefix.
69       * <p>
70       * Not required.
71       *
72       * @param prefix the prefix
73       */
74      public void setPrefix( final String prefix )
75      {
76          this.prefix = format( prefix );
77      }
78  
79      /**
80       * Set the name of the output file.
81       * <p>
82       * Required.
83       *
84       * @param filename the file name
85       */
86      public void setToFile( final String filename )
87      {
88          this.filename = filename;
89      }
90  
91      /**
92       * Set whether the analyzis should stop upon error or not.
93       * <p>
94       * Not required. Default is false.
95       *
96       * @param keepGoing if the analyzis should keep going upon error
97       */
98      public void setKeepGoing( final boolean keepGoing )
99      {
100         this.keepGoing = keepGoing;
101     }
102 
103     /**
104      * Set the number of samples to output.
105      * <p>
106      * Not required. Default is all.
107      *
108      * @param samples truncate the output after this given number of samples
109      */
110     public void setSamples( final int samples )
111     {
112         if( samples < 0 )
113             throw new BuildException( "Parameter 'samples' must be positive" );
114         this.samples = samples;
115     }
116 
117     /**
118      * Set the measurements.
119      * <p>
120      * Not required. Default is "NCSS,CCN,function".
121      *
122      * @param measurements the ordered list of measurements to perform
123      */
124     public void setMeasurements( final String measurements )
125     {
126         this.measurements = measurements;
127     }
128 
129     private String format( final String path )
130     {
131         String result = path.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar );
132         if( result.charAt( result.length() - 1 ) != File.separatorChar )
133             result += File.separatorChar;
134         return result;
135     }
136 
137     /**
138      * Add a define definition.
139      *
140      * @param define the define
141      */
142     public void addConfiguredDefine( final Define define )
143     {
144         if( define.getName() == null )
145             throw new BuildException( "Missing required 'name' for define" );
146         arguments.add( define );
147     }
148 
149     /**
150      * Add a macro definition.
151      *
152      * @param macro the macro
153      */
154     public void addConfiguredMacro( final Macro macro )
155     {
156         if( macro.getName() == null )
157             throw new BuildException( "Missing required 'name' for macro" );
158         arguments.add( macro );
159     }
160 
161     /**
162      * {@inheritDoc}
163      */
164     public void execute()
165     {
166         if( filename == null )
167             throw new BuildException( "Missing 'tofile' attribute to specify output file name" );
168         try
169         {
170             new CppNcss( new Options( buildArguments() ), new AntLogger( this ) ).run();
171         }
172         catch( FileNotFoundException e )
173         {
174             throw new BuildException( e );
175         }
176     }
177 
178     private String[] buildArguments()
179     {
180         final List<String> args = new ArrayList<String>();
181         args.add( "-x" );
182         args.add( "-f=" + filename );
183         if( keepGoing )
184             args.add( "-k" );
185         if( prefix != null )
186             args.add( "-p=" + prefix );
187         args.add( "-n=" + samples );
188         if( measurements != null )
189             args.add( "-m=" + measurements );
190         for( Argument argument : arguments )
191             args.add( argument.toArgument() );
192         for( FileSet fileset : filesets )
193         {
194             final DirectoryScanner scanner = fileset.getDirectoryScanner( getProject() );
195             final String directory = format( scanner.getBasedir().toString() );
196             for( String file : scanner.getIncludedFiles() )
197                 args.add( directory + file );
198         }
199         return args.toArray( new String[args.size()] );
200     }
201 
202     /**
203      * Defines an element convertible to a command line argument.
204      *
205      * @author Mathieu Champlon
206      */
207     private static interface Argument
208     {
209         String toArgument();
210     }
211 
212     /**
213      * Provides a symbol definition.
214      *
215      * @author Mathieu Champlon
216      */
217     public static class Symbol implements Argument
218     {
219         private String name;
220         private String value;
221         private final String prefix;
222 
223         /**
224          * Create a symbol.
225          *
226          * @param prefix the command line option prefix
227          */
228         protected Symbol( final String prefix )
229         {
230             this.prefix = prefix;
231         }
232 
233         /**
234          * Sets the name.
235          * <p>
236          * Required.
237          *
238          * @param name the name
239          */
240         public final void setName( final String name )
241         {
242             this.name = name;
243         }
244 
245         /**
246          * Retrieve the name.
247          *
248          * @return the name
249          */
250         public final String getName()
251         {
252             return name;
253         }
254 
255         /**
256          * Sets the macro value.
257          * <p>
258          * Required.
259          *
260          * @param value the value
261          */
262         public final void setValue( final String value )
263         {
264             this.value = value;
265         }
266 
267         /**
268          * Retrieve the value.
269          *
270          * @return the value
271          */
272         public final String getValue()
273         {
274             return value;
275         }
276 
277         /**
278          * Create the corresponding command line argument.
279          *
280          * @return the formatted argument
281          */
282         public final String toArgument()
283         {
284             if( value == null )
285                 return "-" + prefix + name;
286             return "-" + prefix + name + '=' + value;
287         }
288     }
289 
290     /**
291      * Provides a define definition.
292      *
293      * @author Mathieu Champlon
294      */
295     public static final class Define extends Symbol
296     {
297         /**
298          * Create a define symbol.
299          */
300         public Define()
301         {
302             super( "D" );
303         }
304     }
305 
306     /**
307      * Provides a macro definition.
308      *
309      * @author Mathieu Champlon
310      */
311     public static final class Macro extends Symbol
312     {
313         /**
314          * Create a macro symbol.
315          */
316         public Macro()
317         {
318             super( "M" );
319         }
320     }
321 }