001    /*
002    Copyright (C) 2000 Chr. Clemens Lee <clemens@kclee.com>.
003    
004    This file is part of JavaNCSS
005    (http://www.kclee.com/clemens/java/javancss/).
006    
007    JavaNCSS is free software; you can redistribute it and/or modify it
008    under the terms of the GNU General Public License as published by the
009    Free Software Foundation; either version 2, or (at your option) any
010    later version.
011    
012    JavaNCSS is distributed in the hope that it will be useful, but WITHOUT
013    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
015    for more details.
016    
017    You should have received a copy of the GNU General Public License
018    along with JavaNCSS; see the file COPYING.  If not, write to
019    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
020    Boston, MA 02111-1307, USA.  */
021    
022    package javancss;
023    
024    import java.awt.event.WindowAdapter;
025    import java.awt.event.WindowEvent;
026    import java.io.File;
027    import java.io.FileInputStream;
028    import java.io.FileNotFoundException;
029    import java.io.FileOutputStream;
030    import java.io.InputStream;
031    import java.io.IOException;
032    import java.io.InputStreamReader;
033    import java.io.OutputStream;
034    import java.io.OutputStreamWriter;
035    import java.io.PrintWriter;
036    import java.io.Reader;
037    import java.io.UnsupportedEncodingException;
038    import java.util.ArrayList;
039    import java.util.Collections;
040    import java.util.HashMap;
041    import java.util.HashSet;
042    import java.util.Iterator;
043    import java.util.List;
044    import java.util.Map;
045    import java.util.Set;
046    
047    import ccl.util.Exitable;
048    import ccl.util.FileUtil;
049    import ccl.util.Init;
050    import ccl.util.Util;
051    
052    import javancss.parser.JavaParser;
053    import javancss.parser.JavaParserInterface;
054    import javancss.parser.JavaParserTokenManager;
055    import javancss.parser.ParseException;
056    import javancss.parser.TokenMgrError;
057    import javancss.parser.debug.JavaParserDebug;
058    import javancss.parser.java15.JavaParser15;
059    import javancss.parser.java15.debug.JavaParser15Debug;
060    import javancss.test.JavancssTest;
061    
062    /**
063     * While the Java parser class might be the heart of JavaNCSS,
064     * this class is the brain. This class controls input and output and
065     * invokes the Java parser.
066     *
067     * @author    Chr. Clemens Lee <clemens@kclee.com>
068     *            , recursive feature by P??k? Hannu
069     *            , additional javadoc metrics by Emilio Gongora <emilio@sms.nl>
070     *            , and Guillermo Rodriguez <guille@sms.nl>.
071     * @version   $Id: Javancss.java 157 2009-05-24 06:59:58Z hboutemy $
072     */
073    public class Javancss implements Exitable
074    {
075        private static final String S_INIT__FILE_CONTENT =
076            "[Init]\n" +
077            "Author=Chr. Clemens Lee\n" +
078            "\n" +
079            "[Help]\n"+
080            "; Please do not edit the Help section\n"+
081            "HelpUsage=@srcfiles.txt | *.java | <stdin>\n" +
082            "Options=ncss,package,object,function,all,gui,xml,out,recursive,check,encoding,parser15\n" +
083            "ncss=b,o,Counts the program NCSS (default).\n" +
084            "package=b,o,Assembles a statistic on package level.\n" +
085            "object=b,o,Counts the object NCSS.\n" +
086            "function=b,o,Counts the function NCSS.\n" +
087            "all=b,o,The same as '-function -object -package'.\n" +
088            "gui=b,o,Opens a gui to present the '-all' output in tabbed panels.\n" +
089            "xml=b,o,Output in xml format.\n" +
090            "out=s,o,Output file name. By default output goes to standard out.\n"+
091            "recursive=b,o,Recurse to subdirs.\n" +
092            "check=b,o,Triggers a javancss self test.\n" +
093            "encoding=s,o,Encoding used while reading source files (default: platform encoding).\n" +
094            "parser15=b,o,Use new experimental Java 1.5 parser.\n" +
095            "\n" +
096            "[Colors]\n" +
097            "UseSystemColors=true\n";
098    
099        private boolean _bExit = false;
100    
101        private List/*<File>*/ _vJavaSourceFiles = null;
102        private String encoding = null;
103    
104        private String _sErrorMessage = null;
105        private Throwable _thrwError = null;
106    
107        private JavaParserInterface _pJavaParser = null;
108        private int _ncss = 0;
109        private int _loc = 0;
110        private List/*<FunctionMetric>*/ _vFunctionMetrics = new ArrayList();
111        private List/*<ObjectMetric>*/ _vObjectMetrics = new ArrayList();
112        private List/*<PackageMetric>*/ _vPackageMetrics = null;
113        private List _vImports = null;
114        private Map/*<String,PackageMetric>*/ _htPackages = null;
115        private Object[] _aoPackage = null;
116    
117        /**
118         * Just used for parseImports.
119         */
120        private File _sJavaSourceFile = null;
121    
122        private Reader createSourceReader( File sSourceFile_ )
123        {
124            try
125            {
126                return newReader( sSourceFile_ );
127            }
128            catch ( IOException pIOException )
129            {
130                if ( Util.isEmpty( _sErrorMessage ) )
131                {
132                    _sErrorMessage = "";
133                }
134                else
135                {
136                    _sErrorMessage += "\n";
137                }
138                _sErrorMessage += "File not found: " + sSourceFile_.getAbsolutePath();
139                _thrwError = pIOException;
140    
141                return null;
142            }
143        }
144    
145        private void _measureSource( File sSourceFile_ ) throws IOException, Exception, Error
146        {
147            Reader reader = null;
148    
149            // opens the file
150            try
151            {
152                reader = newReader( sSourceFile_ );
153            }
154            catch ( IOException pIOException )
155            {
156                if ( Util.isEmpty( _sErrorMessage ) )
157                {
158                    _sErrorMessage = "";
159                }
160                else
161                {
162                    _sErrorMessage += "\n";
163                }
164                _sErrorMessage += "File not found: " + sSourceFile_.getAbsolutePath();
165                _thrwError = pIOException;
166    
167                throw pIOException;
168            }
169    
170            String sTempErrorMessage = _sErrorMessage;
171            try
172            {
173                // the same method but with a Reader
174                _measureSource( reader );
175            }
176            catch ( Exception pParseException )
177            {
178                if ( sTempErrorMessage == null )
179                {
180                    sTempErrorMessage = "";
181                }
182                sTempErrorMessage += "ParseException in " + sSourceFile_.getAbsolutePath() +
183                       "\nLast useful checkpoint: \"" + _pJavaParser.getLastFunction() + "\"\n";
184                sTempErrorMessage += pParseException.getMessage() + "\n";
185    
186                _sErrorMessage = sTempErrorMessage;
187                _thrwError = pParseException;
188    
189                throw pParseException;
190            }
191            catch ( Error pTokenMgrError )
192            {
193                if ( sTempErrorMessage == null )
194                {
195                    sTempErrorMessage = "";
196                }
197                sTempErrorMessage += "TokenMgrError in " + sSourceFile_.getAbsolutePath() +
198                       "\n" + pTokenMgrError.getMessage() + "\n";
199                _sErrorMessage = sTempErrorMessage;
200                _thrwError = pTokenMgrError;
201    
202                throw pTokenMgrError;
203            }
204        }
205    
206        private void _measureSource( Reader reader ) throws IOException, Exception, Error
207        {
208          Util.debug( "_measureSource(Reader).ENTER" );
209          //Util.debug( "_measureSource(Reader).parser15: -->" + (_pInit.getOptions().get( "parser15" ) + "<--" );
210          //Util.panicIf( _pInit == null );
211          //Util.panicIf( _pInit.getOptions() == null );
212          Util.debug( "_measureSource(Reader).ENTER2" );
213          try
214          {
215            // create a parser object
216            if ( Util.isDebug() == false )
217            {
218              if ( _pInit == null || _pInit.getOptions() == null || _pInit.getOptions().get( "parser15" ) == null ) {
219                Util.debug( "creating JavaParser" );
220                _pJavaParser = (JavaParserInterface)(new JavaParser( reader ));
221              } else {
222                Util.debug( "creating JavaParser15" );
223                _pJavaParser = (JavaParserInterface)(new JavaParser15( reader ));
224              }
225            } else {
226              if ( _pInit == null || _pInit.getOptions() == null || _pInit.getOptions().get( "parser15" ) == null ) {
227                Util.debug( "creating JavaParserDebug" );
228                Util.println( "creating JavaParserDebug" );
229                _pJavaParser = (JavaParserInterface)(new JavaParserDebug( reader ));
230              } else {
231                Util.debug( "creating JavaParser15Debug" );
232                _pJavaParser = (JavaParserInterface)(new JavaParser15Debug( reader ));
233              }
234            }
235    
236                // execute the parser
237                _pJavaParser.parse();
238                Util.debug( "Javancss._measureSource(DataInputStream).SUCCESSFULLY_PARSED" );
239    
240                _ncss += _pJavaParser.getNcss(); // increment the ncss
241                _loc += _pJavaParser.getLOC(); // and loc
242                // add new data to global vector
243                _vFunctionMetrics.addAll( _pJavaParser.getFunction() );
244                _vObjectMetrics.addAll( _pJavaParser.getObject() );
245                Map htNewPackages = _pJavaParser.getPackage();
246    
247                /* List vNewPackages = new Vector(); */
248                for ( Iterator ePackages = htNewPackages.entrySet().iterator(); ePackages.hasNext(); )
249                {
250                    String sPackage = (String) ( (Map.Entry) ePackages.next() ).getKey();
251    
252                    PackageMetric pckmNext = (PackageMetric) htNewPackages.get( sPackage );
253                    pckmNext.name = sPackage;
254    
255                    PackageMetric pckmPrevious = (PackageMetric) _htPackages.get( sPackage );
256                    pckmNext.add( pckmPrevious );
257    
258                    _htPackages.put( sPackage, pckmNext );
259                }
260            }
261            catch ( Exception pParseException )
262            {
263                if ( _sErrorMessage == null )
264                {
265                    _sErrorMessage = "";
266                }
267                _sErrorMessage += "ParseException in STDIN";
268                if ( _pJavaParser != null )
269                {
270                    _sErrorMessage += "\nLast useful checkpoint: \"" + _pJavaParser.getLastFunction() + "\"\n";
271                }
272                _sErrorMessage += pParseException.getMessage() + "\n";
273                _thrwError = pParseException;
274    
275                throw pParseException;
276            }
277            catch ( Error pTokenMgrError )
278            {
279                if ( _sErrorMessage == null )
280                {
281                    _sErrorMessage = "";
282                }
283                _sErrorMessage += "TokenMgrError in STDIN\n";
284                _sErrorMessage += pTokenMgrError.getMessage() + "\n";
285                _thrwError = pTokenMgrError;
286    
287                throw pTokenMgrError;
288            }
289        }
290    
291        private void _measureFiles( List/*<File>*/ vJavaSourceFiles_ ) throws IOException, ParseException, TokenMgrError
292        {
293            // for each file
294            for ( Iterator e = vJavaSourceFiles_.iterator(); e.hasNext(); )
295            {
296                File file = (File) e.next();
297    
298                try
299                {
300                    _measureSource( file );
301                }
302                catch ( Throwable pThrowable )
303                {
304                    // hmm, do nothing? Use getLastError() or so to check for details.
305                }
306            }
307        }
308    
309        /**
310         * If arguments were provided, they are used, otherwise
311         * the input stream is used.
312         */
313        private void _measureRoot( Reader reader ) throws IOException, Exception, Error
314        {
315            _htPackages = new HashMap();
316    
317            // either there are argument files, or stdin is used
318            if ( _vJavaSourceFiles == null )
319            {
320                _measureSource( reader );
321            }
322            else
323            {
324                // the collection of files get measured
325                _measureFiles( _vJavaSourceFiles );
326            }
327    
328            _vPackageMetrics = new ArrayList();
329            for ( Iterator ePackages = _htPackages.keySet().iterator(); ePackages.hasNext(); )
330            {
331                String sPackage = (String) ePackages.next();
332    
333                PackageMetric pckmNext = (PackageMetric) _htPackages.get( sPackage );
334                _vPackageMetrics.add( pckmNext );
335            }
336            Collections.sort( _vPackageMetrics );
337        }
338    
339        public List getImports() {
340            return _vImports;
341        }
342    
343        /**
344         * Return info about package statement.
345         * First element has name of package,
346         * then begin of line, etc.
347         */
348        public Object[] getPackage() {
349            return _aoPackage;
350        }
351    
352        /**
353         * The same as getFunctionMetrics?!
354         */
355        public List/*<FunctionMetric>*/ getFunctions() {
356            return _vFunctionMetrics;
357        }
358    
359        public String printObjectNcss() {
360            return getFormatter().printObjectNcss();
361        }
362    
363        public String printFunctionNcss() {
364            return getFormatter().printFunctionNcss();
365        }
366    
367        public String printPackageNcss() {
368            return getFormatter().printPackageNcss();
369        }
370    
371        public String printJavaNcss() {
372            return getFormatter().printJavaNcss();
373        }
374    
375        public Javancss( List/*<File>*/ vJavaSourceFiles_ )
376        {
377            _vJavaSourceFiles = vJavaSourceFiles_;
378            try {
379                _measureRoot(newReader(System.in));
380            } catch(Exception e) {
381                e.printStackTrace();
382            } catch(TokenMgrError pError) {
383                pError.printStackTrace();
384            }
385        }
386    
387        public Javancss( File sJavaSourceFile_ )
388        {
389            Util.debug( "Javancss.<init>(String).sJavaSourceFile_: " + sJavaSourceFile_ );
390            _sErrorMessage = null;
391            _vJavaSourceFiles = new ArrayList();
392            _vJavaSourceFiles.add(sJavaSourceFile_);
393            try {
394                _measureRoot(newReader(System.in));
395            } catch(Exception e) {
396                Util.debug( "Javancss.<init>(String).e: " + e );
397                e.printStackTrace();
398            } catch(TokenMgrError pError) {
399                Util.debug( "Javancss.<init>(String).pError: " + pError );
400                pError.printStackTrace();
401            }
402        }
403    
404        /**
405         * Only way to create object that does not immediately
406         * start to parse.
407         */
408        public Javancss() {
409            super();
410    
411            _sErrorMessage = null;
412            _thrwError = null;
413        }
414    
415        public boolean parseImports() {
416            if ( _sJavaSourceFile == null ) {
417                Util.debug( "Javancss.parseImports().NO_FILE" );
418    
419                return true;
420            }
421            Reader reader = createSourceReader( _sJavaSourceFile );
422            if ( reader == null ) {
423                Util.debug( "Javancss.parseImports().NO_DIS" );
424    
425                return true;
426            }
427    
428            try {
429                Util.debug( "Javancss.parseImports().START_PARSING" );
430                if ( Util.isDebug() == false ) {
431                  _pJavaParser = (JavaParserInterface)(new JavaParser(reader));
432                } else {
433                  _pJavaParser = (JavaParserInterface)(new JavaParserDebug(reader));
434                }
435                _pJavaParser.parseImportUnit();
436                _vImports = _pJavaParser.getImports();
437                _aoPackage = _pJavaParser.getPackageObjects();
438                Util.debug( "Javancss.parseImports().END_PARSING" );
439            } catch(Exception pParseException) {
440                Util.debug( "Javancss.parseImports().PARSE_EXCEPTION" );
441                if (_sErrorMessage == null) {
442                    _sErrorMessage = "";
443                }
444                _sErrorMessage += "ParseException in STDIN";
445                if (_pJavaParser != null) {
446                    _sErrorMessage += "\nLast useful checkpoint: \"" + _pJavaParser.getLastFunction() + "\"\n";
447                }
448                _sErrorMessage += pParseException.getMessage() + "\n";
449                _thrwError = pParseException;
450    
451                return true;
452            } catch(Error pTokenMgrError) {
453                Util.debug( "Javancss.parseImports().TOKEN_ERROR" );
454                if (_sErrorMessage == null) {
455                    _sErrorMessage = "";
456                }
457                _sErrorMessage += "TokenMgrError in STDIN\n";
458                _sErrorMessage += pTokenMgrError.getMessage() + "\n";
459                _thrwError = pTokenMgrError;
460    
461                return true;
462            }
463    
464            return false;
465        }
466    
467        public void setSourceFile( File javaSourceFile_ ) {
468            _sJavaSourceFile = javaSourceFile_;
469            _vJavaSourceFiles = new ArrayList();
470            _vJavaSourceFiles.add(javaSourceFile_);
471        }
472    
473        public Javancss(Reader reader) {
474            try {
475                _measureRoot(reader);
476            } catch(Exception e) {
477            } catch(TokenMgrError pError) {
478            }
479        }
480    
481        /**
482         * recursively adds *.java files
483         * @param dir the base directory to search
484         * @param v the list of file to add found files to
485         */
486        private static void _addJavaFiles( File dir, List v/*<File>*/ )
487        {
488            File[] files = dir.listFiles();
489            if( files == null || files.length == 0 )
490            {
491                return;
492            }
493    
494            for( int i = 0; i < files.length; i++ )
495            {
496                File newFile = files[i];
497                if( newFile.isDirectory() )
498                {
499                    //Recurse!!!
500                    _addJavaFiles( newFile, v );
501                }
502                else
503                {
504                    if( newFile.getName().endsWith( ".java" ) )
505                    {
506                        v.add( newFile );
507                    }
508                }
509            }
510        }
511    
512        private List/*<File>*/ findFiles( List/*<String>*/ filenames, boolean recursive ) throws IOException
513        {
514            if ( Util.isDebug() )
515            {
516                Util.debug( "filenames: " + Util.toString( filenames ) );
517            }
518            if ( filenames.size() == 0 )
519            {
520                if ( recursive )
521                {
522                    // If no files then add current directory!
523                    filenames.add( "." );
524                }
525                else
526                {
527                    return null;
528                }
529            }
530    
531            Set _processedAtFiles = new HashSet();
532            List newFiles = new ArrayList();
533            for ( Iterator iter = filenames.iterator(); iter.hasNext(); )
534            {
535                String filename = (String)iter.next();
536    
537                // if the file specifies other files...
538                if ( filename.startsWith( "@" ) )
539                {
540                    filename = filename.substring( 1 );
541                    if ( filename.length() > 1 )
542                    {
543                        filename = FileUtil.normalizeFileName( filename );
544                        if ( _processedAtFiles.add( filename ) )
545                        {
546                            String sJavaSourceFileNames = null;
547                            try
548                            {
549                                sJavaSourceFileNames = FileUtil.readFile( filename );
550                            }
551                            catch( IOException pIOException )
552                            {
553                                _sErrorMessage = "File Read Error: " + filename;
554                                _thrwError = pIOException;
555                                throw pIOException;
556                            }
557                            List vTheseJavaSourceFiles = Util.stringToLines( sJavaSourceFileNames );
558                            for ( Iterator iterator = vTheseJavaSourceFiles.iterator(); iterator.hasNext(); )
559                            {
560                                newFiles.add( new File( (String)iterator.next() ) );
561                            }
562                        }
563                    }
564                }
565                else
566                {
567                    filename = FileUtil.normalizeFileName( filename );
568                    File file = new File( filename );
569                    if ( file.isDirectory() )
570                    {
571                        _addJavaFiles( file, newFiles );
572                    }
573                    else
574                    {
575                        newFiles.add( file );
576                    }
577                }
578            }
579    
580            if ( Util.isDebug() )
581            {
582                Util.debug( "resolved filenames: " + Util.toString( newFiles ) );
583            }
584    
585            return newFiles;
586        }
587    
588        private Init _pInit = null;
589    
590        /**
591         * @deprecated use Javancss(String[]) instead, since the sRcsHeader_ parameter is not useful
592         */
593        public Javancss(String[] asArgs_, String sRcsHeader_) throws IOException {
594            this(asArgs_);
595        }
596    
597        /**
598         * This is the constructor used in the main routine in
599         * javancss.Main.
600         * Other constructors might be helpful to use Javancss out
601         * of other programs.
602         */
603        public Javancss(String[] asArgs_) throws IOException {
604            _pInit = new Init(this, asArgs_, Main.S_RCS_HEADER, S_INIT__FILE_CONTENT);
605            if (_bExit) {
606                return;
607            }
608            Map htOptions = _pInit.getOptions();
609    
610            setEncoding( (String) htOptions.get( "encoding" ) );
611    
612            if ( htOptions.get( "check" ) != null ) {
613                new JavancssTest().main( new File( _pInit.getApplicationPath() ) );
614                return;
615            }
616    
617            // the arguments (the files) to be processed
618            _vJavaSourceFiles = findFiles( _pInit.getArguments(), htOptions.get( "recursive" ) != null );
619    
620    //        if ( htOptions.get( "gui" ) != null )
621    //        {
622    //            final JavancssFrame pJavancssFrame = new JavancssFrame(_pInit);
623    //            /*final Thread pThread = Thread.currentThread();*/
624    //            pJavancssFrame.addWindowListener(new WindowAdapter() {
625    //                    public void windowClosing(WindowEvent e_) {
626    //                        Util.debug("JavancssAll.run().WindowAdapter.windowClosing().1");
627    //                        pJavancssFrame.setVisible(false);
628    //                        pJavancssFrame.dispose();
629    //                    }
630    //                });
631    //            pJavancssFrame.setVisible(true);
632    //
633    //            try {
634    //                _measureRoot(newReader(System.in));
635    //            } catch(Throwable pThrowable) {
636    //                // shouldn't we print something here?
637    //            }
638    //
639    //            pJavancssFrame.showJavancss(this);
640    //            pJavancssFrame.setSelectedTab(JavancssFrame.S_PACKAGES);
641    //            pJavancssFrame.run();
642    //
643    //            return;
644    //        }
645    
646            // this initiates the measurement
647            try
648            {
649                _measureRoot( newReader( System.in ) );
650            }
651            catch(Throwable pThrowable)
652            {
653            }
654            if ( getLastErrorMessage() != null )
655            {
656                Util.printlnErr( getLastErrorMessage() + "\n" );
657                if ( getNcss() <= 0 )
658                {
659                    return;
660                }
661            }
662    
663            boolean bNoNCSS = false;
664    
665            String sOutputFile = (String)htOptions.get( "out" );
666            OutputStream out = System.out;
667            if (sOutputFile != null)
668            {
669                try
670                {
671                    out = new FileOutputStream( FileUtil.normalizeFileName( sOutputFile ) );
672                } catch ( Exception exception ) {
673                    Util.printlnErr( "Error opening output file '"
674                                     + sOutputFile
675                                     + "': " + exception.getMessage() );
676    
677                    out = System.out;
678                    sOutputFile = null;
679                }
680            }
681            // TODO: encoding configuration support for result output
682            PrintWriter pw = useXML() ? new PrintWriter(new OutputStreamWriter(out, "UTF-8")) : new PrintWriter(out);
683    
684            if ( useXML() )
685            {
686                pw.print( XmlFormatter.printStart() );
687            }
688    
689            if (htOptions.get( "package" ) != null ||
690                htOptions.get( "all" ) != null)
691            {
692                pw.print( printPackageNcss() );
693                bNoNCSS = true;
694            }
695            if (htOptions.get( "object" ) != null ||
696                htOptions.get( "all" ) != null)
697            {
698                if ( bNoNCSS )
699                {
700                    pw.println();
701                }
702                pw.print( printObjectNcss() );
703                bNoNCSS = true;
704            }
705            if (htOptions.get( "function" ) != null ||
706                htOptions.get( "all" ) != null)
707            {
708                if ( bNoNCSS )
709                {
710                    pw.println();
711                }
712                pw.print( printFunctionNcss() );
713                bNoNCSS = true;
714            }
715            if (!bNoNCSS) {
716                pw.print( printJavaNcss() );
717            }
718    
719            if ( useXML() )
720            {
721                if ( !bNoNCSS )
722                {
723                    pw.print( printJavaNcss() );
724                }
725                pw.println( "</javancss>" );
726            }
727    
728            if ( sOutputFile != null )
729            {
730                pw.close();
731            } else
732            {
733                // stdout is used: don't close but ensure everything is flushed
734                pw.flush();
735            }
736        }
737    
738        public int getNcss() {
739            return _ncss;
740        }
741    
742        public int getLOC() {
743            return _loc;
744        }
745    
746        // added by SMS
747        public int getJvdc() {
748            return _pJavaParser.getJvdc();
749        }
750    
751        /**
752         * JDCL stands for javadoc comment lines (while jvdc stands
753         * for number of javadoc comments).
754         */
755        public int getJdcl() {
756            return JavaParserTokenManager._iFormalComments;
757        }
758    
759        public int getSl() {
760            return JavaParserTokenManager._iSingleComments;
761        }
762    
763        public int getMl() {
764            return JavaParserTokenManager._iMultiComments;
765        }
766        //
767    
768        public List getFunctionMetrics() {
769            return(_vFunctionMetrics);
770        }
771    
772        public List/*<ObjectMetric>*/ getObjectMetrics() {
773            return(_vObjectMetrics);
774        }
775    
776        /**
777         * Returns list of packages in the form
778         * PackageMetric objects.
779         */
780        public List getPackageMetrics() {
781            return(_vPackageMetrics);
782        }
783    
784        public String getLastErrorMessage() {
785            if (_sErrorMessage == null) {
786                return null;
787            }
788            return _sErrorMessage;
789        }
790    
791        public Throwable getLastError() {
792            return _thrwError;
793        }
794    
795        public void setExit() {
796            _bExit = true;
797        }
798    
799        private boolean _bXML = false;
800    
801        public void setXML( boolean bXML )
802        {
803            _bXML = bXML;
804        }
805    
806        public boolean useXML()
807        {
808            return _bXML
809                   || (_pInit != null && _pInit.getOptions().get( "xml" ) != null );
810        }
811    
812        public Formatter getFormatter()
813        {
814            if ( useXML() )
815            {
816                return new XmlFormatter( this );
817            }
818    
819            return new AsciiFormatter( this );
820        }
821    
822        public String getEncoding()
823        {
824            return encoding;
825        }
826    
827        public void setEncoding( String encoding )
828        {
829            this.encoding = encoding;
830        }
831    
832        private Reader newReader( InputStream stream ) throws UnsupportedEncodingException
833        {
834            return ( encoding == null ) ? new InputStreamReader( stream ) : new InputStreamReader( stream, encoding );
835        }
836    
837        private Reader newReader( File file ) throws FileNotFoundException, UnsupportedEncodingException
838        {
839            return newReader( new FileInputStream( file ) );
840        }
841    }