/* * CodeEval - The Code Evaluation Package for Java. * * Copyright (c) 1997-99 California Institute of Technology and Joseph R. Kiniry. * All Rights Reserved. * * $Id$ */ import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.InputStreamReader; import java.io.IOException; /** * JCC - The Java Comment Counter - A program that determines how well you are commenting your Java * code. * * JCC counts the lines of code and comments in a java file of set of java files. All whitespace * comments and code lines are not counted nor are lines of code less than 3 characters long. Lines * with only a solitary brace are examples of lines that are not counted. Final output to stdout is * the totals for lines of code, lines of comments, and a ratio (comments/total). * * Horribly commented code averages %0-%10 comment ratio. * Poorly commented code has a %10-%20 comment ratio. * Average code has a %20-%30 comment ratio. * Good code has a %30-%50 comment ratio. * Excellent code has a > %50 comment ratio. * * @version 0.07 Wed Aug 11 00:02:20 PDT 1999 * @version $Revision$ * @author Joseph R. Kiniry * * @history Several versions of this class were developed. First under JDK 1.0 as * edu.caltech.cs.kiniry.coding.CommentCounter in mid-1997, then under JDK 1.1 as * edu.caltech.cs.infospheres.util.CommentCounter in late-1997. This version is the next stage in * CommentCounter's evolution and has now been named JCC and is released under the Infospheres web * page. **/ public class JCC { /** * Since this code is strictly sequential; i.e. works on exactly one set of input and exits, we * don't need to define any objects, methods, etc. other than main. * * * @example JCC is used to either process a single file provided on the command line or a data * stream provided via System.in (STDIN). For example: * <PRE> * <CODE> * "java JCC file1.java" * </CODE> * </PRE> * will read and analyze the file "file1.java", but * <PRE> * <CODE> * "cat *.java | java JCC" * </CODE> * </PRE> * will pipe the contents of all files ending in the suffix ".java" to the JCC for analysis. * * @exception IOException is thrown if there is a problem reading the input stream or data file. * @exception FileNotFoundException IF * ((args.length > 0 && (File(args[0]).exists() == false) || * (File(args[0]).canRead() == false) || * (File(args[0]).isFile() == false))) * If we are supplied with a filename, and it is bogus for some reason, throw this exception. * @param args The arguments passed to the program on the command line. If a single argument is * passed, it is used as the name of a Java source file that is to be processed. If no arguments * are passed, input is expected on the stream System.in (STDIN). * * @ensures Output total lines of code, total number of lines of comments, and ratio of * comment/code to the user. * * @values (number_lines >= 0) * @values (number_comments >= 0) * * @see * @design - Short (and empty) comments are not considered worthy of being counted. Empty lines * are ignored as well. @modifies - Only local variables. (in, debug, number_lines, * number_comments, inside_comment, and s) **/ public static void main (String [] args) throws FileNotFoundException, IOException { // All local instance variables. // The input reader from which we read Java code. BufferedReader in = null; // A switch used to turn on and off debugging. boolean debug = false; // The total number of legitimate lines of code we have counted. int number_lines = 0; // The total number of legitimate comments we have counted. int number_comments = 0; // A flag indicating if we are inside of a comment or not. boolean inside_comment = false; // The current line of code we are examining. String s; // Construct a proper stream from which we can read information. if (args.length == 1) in = new BufferedReader(new FileReader(args[0])); else in = new BufferedReader(new InputStreamReader(System.in)); // Read in lines of code from the stream until we reach the end // of the input. while ((s = in.readLine()) != null) { int pre_trim_length = s.length(); int trim_length = (new String(s)).trim().length(); if (debug) { System.err.println("Line read: " + s); System.err.println("\tpre_trim_length: " + pre_trim_length); System.err.println("\ttrim_length: " + trim_length); } // if line has "/*" followed by "*/" then bump # of comments if ((s.indexOf("/*") != -1) && (s.indexOf("*/") != -1)) { if (debug) System.err.println("\t\tcontained comment"); if (s.trim().length() > 6) if (debug) { System.err.println ("\t\tcontained comment of proper length"); number_comments ++; } } else if (s.indexOf("//") != -1) { // if line has "//" bump number of comments if (debug) System.err.println("\t\tdouble-slash comment"); if (s.trim().length() > 3) { if (debug) System.err.println ("\t\tdouble-slash comment of proper length"); number_comments ++; } } else if ((s.indexOf("/*") != -1) && (s.indexOf("*/") == -1)) { // if we just see a "/*" then we are moving inside a comment inside_comment = true; if (debug) System.err.println("\t\tstarting comment"); if (s.trim().length() > 3) { number_comments ++; if (debug) System.err.println("\t\tstarting comment of proper length"); } } else if ((s.indexOf("/*") == -1) && (s.indexOf("*/") != -1)) { // if we are inside a comment and we see a "*/" then we end it if (debug) System.err.println("\t\tending a multi-line comment"); inside_comment = false; if (s.trim().length() > 3) { if (debug) System.err.println("\t\tending a multi-line comment" + " of proper length"); number_comments ++; } } else if (inside_comment) { // number number of comments if we are inside a comment and not // on an all whitespace line if (debug) System.err.println("\t\tinside multi-line comment"); if (s.trim().length() > 3) { number_comments ++; if (debug) System.err.println("\t\tinside multi-line comment " + "of proper length"); } } // bump number of lines only if we are not on a line of all whitespace if (s.trim().length() > 3) { number_lines ++; if (debug) System.err.println("\t\tline worth counting"); } else if (debug) System.err.println("\t\tline NOT worth counting"); } // print out total number of lines System.out.println("Total number of lines of code: " + number_lines); // print out total number of comments System.out.println("Total number of lines of comments: " + number_comments); // print out ratio comments/lines System.out.println("Ratio (comments/code): " + (int)((float)number_comments/number_lines*100+0.5) + "%"); } }