home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Ebooks / Thinking in Java / c17 / ClassScanner.java next >
Encoding:
Java Source  |  2000-05-25  |  9.6 KB  |  295 lines

  1. //: ClassScanner.java
  2. //////////////////////////////////////////////////
  3. // Copyright (c) Bruce Eckel, 1998
  4. // Source code file from the book "Thinking in Java"
  5. // All rights reserved EXCEPT as allowed by the
  6. // following statements: You can freely use this file
  7. // for your own work (personal or commercial),
  8. // including modifications and distribution in
  9. // executable form only. Permission is granted to use
  10. // this file in classroom situations, including its
  11. // use in presentation materials, as long as the book
  12. // "Thinking in Java" is cited as the source. 
  13. // Except in classroom situations, you cannot copy
  14. // and distribute this code; instead, the sole
  15. // distribution point is http://www.BruceEckel.com 
  16. // (and official mirror sites) where it is
  17. // freely available. You cannot remove this
  18. // copyright and notice. You cannot distribute
  19. // modified versions of the source code in this
  20. // package. You cannot use this file in printed
  21. // media without the express permission of the
  22. // author. Bruce Eckel makes no representation about
  23. // the suitability of this software for any purpose.
  24. // It is provided "as is" without express or implied
  25. // warranty of any kind, including any implied
  26. // warranty of merchantability, fitness for a
  27. // particular purpose or non-infringement. The entire
  28. // risk as to the quality and performance of the
  29. // software is with you. Bruce Eckel and the
  30. // publisher shall not be liable for any damages
  31. // suffered by you or any third party as a result of
  32. // using or distributing software. In no event will
  33. // Bruce Eckel or the publisher be liable for any
  34. // lost revenue, profit, or data, or for direct,
  35. // indirect, special, consequential, incidental, or
  36. // punitive damages, however caused and regardless of
  37. // the theory of liability, arising out of the use of
  38. // or inability to use software, even if Bruce Eckel
  39. // and the publisher have been advised of the
  40. // possibility of such damages. Should the software
  41. // prove defective, you assume the cost of all
  42. // necessary servicing, repair, or correction. If you
  43. // think you've found an error, please email all
  44. // modified files with clearly commented changes to:
  45. // Bruce@EckelObjects.com. (Please use the same
  46. // address for non-code errors found in the book.)
  47. /////////////////////////////////////////////////
  48.  
  49. // Scans all files in directory for classes
  50. // and identifiers, to check capitalization.
  51. // Assumes properly compiling code listings.
  52. // Doesn't do everything right, but is a very
  53. // useful aid.
  54. import java.io.*;
  55. import java.util.*;
  56.  
  57. class MultiStringMap extends Hashtable {
  58.   public void add(String key, String value) {
  59.     if(!containsKey(key))
  60.       put(key, new Vector());
  61.     ((Vector)get(key)).addElement(value);
  62.   }
  63.   public Vector getVector(String key) {
  64.     if(!containsKey(key)) {
  65.       System.err.println(
  66.         "ERROR: can't find key: " + key);
  67.       System.exit(1);
  68.     }
  69.     return (Vector)get(key);
  70.   }
  71.   public void printValues(PrintStream p) {
  72.     Enumeration k = keys();
  73.     while(k.hasMoreElements()) {
  74.       String oneKey = (String)k.nextElement();
  75.       Vector val = getVector(oneKey);
  76.       for(int i = 0; i < val.size(); i++)
  77.         p.println((String)val.elementAt(i));
  78.     }
  79.   }
  80. }
  81.  
  82. public class ClassScanner {
  83.   private File path;
  84.   private String[] fileList;
  85.   private Properties classes = new Properties();
  86.   private MultiStringMap 
  87.     classMap = new MultiStringMap(),
  88.     identMap = new MultiStringMap();
  89.   private StreamTokenizer in;
  90.   public ClassScanner() {
  91.     path = new File(".");
  92.     fileList = path.list(new JavaFilter());
  93.     for(int i = 0; i < fileList.length; i++) {
  94.       System.out.println(fileList[i]);
  95.       scanListing(fileList[i]);
  96.     }
  97.   }
  98.   void scanListing(String fname) {
  99.     try {
  100.       in = new StreamTokenizer(
  101.           new BufferedReader(
  102.             new FileReader(fname)));
  103.       // Doesn't seem to work:
  104.       // in.slashStarComments(true);
  105.       // in.slashSlashComments(true);
  106.       in.ordinaryChar('/');
  107.       in.ordinaryChar('.');
  108.       in.wordChars('_', '_');
  109.       in.eolIsSignificant(true);
  110.       while(in.nextToken() != 
  111.             StreamTokenizer.TT_EOF) {
  112.         if(in.ttype == '/')
  113.           eatComments();
  114.         else if(in.ttype == 
  115.                 StreamTokenizer.TT_WORD) {
  116.           if(in.sval.equals("class") || 
  117.              in.sval.equals("interface")) {
  118.             // Get class name:
  119.                while(in.nextToken() != 
  120.                      StreamTokenizer.TT_EOF
  121.                      && in.ttype != 
  122.                      StreamTokenizer.TT_WORD)
  123.                  ;
  124.                classes.put(in.sval, in.sval);
  125.                classMap.add(fname, in.sval);
  126.           }
  127.           if(in.sval.equals("import") ||
  128.              in.sval.equals("package"))
  129.             discardLine();
  130.           else // It's an identifier or keyword
  131.             identMap.add(fname, in.sval);
  132.         }
  133.       }
  134.     } catch(IOException e) {
  135.       e.printStackTrace();
  136.     }
  137.   }
  138.   void discardLine() {
  139.     try {
  140.       while(in.nextToken() != 
  141.             StreamTokenizer.TT_EOF
  142.             && in.ttype != 
  143.             StreamTokenizer.TT_EOL)
  144.         ; // Throw away tokens to end of line
  145.     } catch(IOException e) {
  146.       e.printStackTrace();
  147.     }
  148.   }
  149.   // StreamTokenizer's comment removal seemed
  150.   // to be broken. This extracts them:
  151.   void eatComments() {
  152.     try {
  153.       if(in.nextToken() != 
  154.          StreamTokenizer.TT_EOF) {
  155.         if(in.ttype == '/')
  156.           discardLine();
  157.         else if(in.ttype != '*')
  158.           in.pushBack();
  159.         else 
  160.           while(true) {
  161.             if(in.nextToken() == 
  162.               StreamTokenizer.TT_EOF)
  163.               break;
  164.             if(in.ttype == '*')
  165.               if(in.nextToken() != 
  166.                 StreamTokenizer.TT_EOF
  167.                 && in.ttype == '/')
  168.                 break;
  169.           }
  170.       }
  171.     } catch(IOException e) {
  172.       e.printStackTrace();
  173.     }
  174.   }
  175.   public String[] classNames() {
  176.     String[] result = new String[classes.size()];
  177.     Enumeration e = classes.keys();
  178.     int i = 0;
  179.     while(e.hasMoreElements())
  180.       result[i++] = (String)e.nextElement();
  181.     return result;
  182.   }
  183.   public void checkClassNames() {
  184.     Enumeration files = classMap.keys();
  185.     while(files.hasMoreElements()) {
  186.       String file = (String)files.nextElement();
  187.       Vector cls = classMap.getVector(file);
  188.       for(int i = 0; i < cls.size(); i++) {
  189.         String className = 
  190.           (String)cls.elementAt(i);
  191.         if(Character.isLowerCase(
  192.              className.charAt(0)))
  193.           System.out.println(
  194.             "class capitalization error, file: "
  195.             + file + ", class: " 
  196.             + className);
  197.       }
  198.     }
  199.   }
  200.   public void checkIdentNames() {
  201.     Enumeration files = identMap.keys();
  202.     Vector reportSet = new Vector();
  203.     while(files.hasMoreElements()) {
  204.       String file = (String)files.nextElement();
  205.       Vector ids = identMap.getVector(file);
  206.       for(int i = 0; i < ids.size(); i++) {
  207.         String id = 
  208.           (String)ids.elementAt(i);
  209.         if(!classes.contains(id)) {
  210.           // Ignore identifiers of length 3 or
  211.           // longer that are all uppercase
  212.           // (probably static final values):
  213.           if(id.length() >= 3 &&
  214.              id.equals(
  215.                id.toUpperCase()))
  216.             continue;
  217.           // Check to see if first char is upper:
  218.           if(Character.isUpperCase(id.charAt(0))){
  219.             if(reportSet.indexOf(file + id)
  220.                 == -1){ // Not reported yet
  221.               reportSet.addElement(file + id);
  222.               System.out.println(
  223.                 "Ident capitalization error in:"
  224.                 + file + ", ident: " + id);
  225.             }
  226.           }
  227.         }
  228.       }
  229.     }
  230.   }
  231.   static final String usage =
  232.     "Usage: \n" + 
  233.     "ClassScanner classnames -a\n" +
  234.     "\tAdds all the class names in this \n" +
  235.     "\tdirectory to the repository file \n" +
  236.     "\tcalled 'classnames'\n" +
  237.     "ClassScanner classnames\n" +
  238.     "\tChecks all the java files in this \n" +
  239.     "\tdirectory for capitalization errors, \n" +
  240.     "\tusing the repository file 'classnames'";
  241.   private static void usage() {
  242.     System.err.println(usage);
  243.     System.exit(1);
  244.   }
  245.   public static void main(String[] args) {
  246.     if(args.length < 1 || args.length > 2)
  247.       usage();
  248.     ClassScanner c = new ClassScanner();
  249.     File old = new File(args[0]);
  250.     if(old.exists()) {
  251.       try {
  252.         // Try to open an existing 
  253.         // properties file:
  254.         InputStream oldlist =
  255.           new BufferedInputStream(
  256.             new FileInputStream(old));
  257.         c.classes.load(oldlist);
  258.         oldlist.close();
  259.       } catch(IOException e) {
  260.         System.err.println("Could not open "
  261.           + old + " for reading");
  262.         System.exit(1);
  263.       }
  264.     }
  265.     if(args.length == 1) {
  266.       c.checkClassNames();
  267.       c.checkIdentNames();
  268.     }
  269.     // Write the class names to a repository:
  270.     if(args.length == 2) {
  271.       if(!args[1].equals("-a"))
  272.         usage();
  273.       try {
  274.         BufferedOutputStream out =
  275.           new BufferedOutputStream(
  276.             new FileOutputStream(args[0]));
  277.         c.classes.save(out,
  278.           "Classes found by ClassScanner.java");
  279.         out.close();
  280.       } catch(IOException e) {
  281.         System.err.println(
  282.           "Could not write " + args[0]);
  283.         System.exit(1);
  284.       }
  285.     }
  286.   }
  287. }
  288.  
  289. class JavaFilter implements FilenameFilter {
  290.   public boolean accept(File dir, String name) {
  291.     // Strip path information:
  292.     String f = new File(name).getName();
  293.     return f.trim().endsWith(".java");
  294.   }
  295. } ///:~