Home | History | Annotate | Download | only in jdiff
      1 package jdiff;
      2 
      3 import java.io.*;
      4 import java.util.*;
      5 import com.sun.javadoc.*;
      6 
      7 /**
      8  * Class to handle options for JDiff.
      9  *
     10  * See the file LICENSE.txt for copyright details.
     11  * @author Matthew Doar, mdoar (at) pobox.com
     12  */
     13 public class Options {
     14 
     15     /** Default constructor. */
     16     public Options() {
     17     }
     18 
     19     /**
     20      * Returns the "length" of a given option. If an option takes no
     21      * arguments, its length is one. If it takes one argument, its
     22      * length is two, and so on. This method is called by Javadoc to
     23      * parse the options it does not recognize. It then calls
     24      * {@link #validOptions} to validate them.
     25      * <blockquote>
     26      * <b>Note:</b><br>
     27      * The options arrive as case-sensitive strings. For options that
     28      * are not case-sensitive, use toLowerCase() on the option string
     29      * before comparing it.
     30      * </blockquote>
     31      *
     32      * @param option  a String containing an option
     33      * @return an int telling how many components that option has
     34      */
     35     public static int optionLength(String option) {
     36         String opt = option.toLowerCase();
     37 
     38         // Standard options
     39         if (opt.equals("-authorid"))  return 2;
     40         if (opt.equals("-versionid")) return 2;
     41         if (opt.equals("-d"))         return 2;
     42         if (opt.equals("-classlist")) return 1;
     43         if (opt.equals("-title"))     return 2;
     44         if (opt.equals("-docletid"))  return 1;
     45         if (opt.equals("-evident"))   return 2;
     46         if (opt.equals("-skippkg"))   return 2;
     47         if (opt.equals("-skipclass")) return 2;
     48         if (opt.equals("-execdepth")) return 2;
     49         if (opt.equals("-help"))      return 1;
     50         if (opt.equals("-version"))      return 1;
     51         if (opt.equals("-package"))   return 1;
     52         if (opt.equals("-protected")) return 1;
     53         if (opt.equals("-public"))    return 1;
     54         if (opt.equals("-private"))   return 1;
     55         if (opt.equals("-sourcepath")) return 2;
     56 
     57         // Options to control JDiff
     58         if (opt.equals("-apiname"))    return 2;
     59         if (opt.equals("-oldapi"))    return 2;
     60         if (opt.equals("-newapi"))    return 2;
     61 
     62         // Options to control the location of the XML files
     63         if (opt.equals("-apidir"))       return 2;
     64         if (opt.equals("-oldapidir"))    return 2;
     65         if (opt.equals("-newapidir"))    return 2;
     66         if (opt.equals("-usercommentsdir"))    return 2;
     67 
     68 
     69         // Options for the exclusion level for classes and members
     70         if (opt.equals("-excludeclass"))    return 2;
     71         if (opt.equals("-excludemember"))    return 2;
     72 
     73         if (opt.equals("-firstsentence"))    return 1;
     74         if (opt.equals("-docchanges"))    return 1;
     75         if (opt.equals("-packagesonly"))    return 1;
     76         if (opt.equals("-showallchanges"))    return 1;
     77 
     78         // Option to change the location for the existing Javadoc
     79         // documentation for the new API. Default is "../"
     80         if (opt.equals("-javadocnew"))    return 2;
     81         // Option to change the location for the existing Javadoc
     82         // documentation for the old API. Default is null.
     83         if (opt.equals("-javadocold"))    return 2;
     84 
     85         if (opt.equals("-baseuri"))    return 2;
     86 
     87         // Option not to suggest comments at all
     88         if (opt.equals("-nosuggest"))    return 2;
     89 
     90         // Option to enable checking that the comments end with a period.
     91         if (opt.equals("-checkcomments"))    return 1;
     92         // Option to retain non-printing characters in comments.
     93         if (opt.equals("-retainnonprinting"))    return 1;
     94         // Option for the name of the exclude tag
     95         if (opt.equals("-excludetag"))    return 2;
     96         // Generate statistical output
     97         if (opt.equals("-stats"))    return 1;
     98 
     99         // Set the browser window title
    100         if (opt.equals("-windowtitle"))    return 2;
    101         // Set the report title
    102         if (opt.equals("-doctitle"))    return 2;
    103 
    104         return 0;
    105     }//optionLength()
    106 
    107    /**
    108     * After parsing the available options using {@link #optionLength},
    109     * Javadoc invokes this method with an array of options-arrays, where
    110     * the first item in any array is the option, and subsequent items in
    111     * that array are its arguments. So, if -print is an option that takes
    112     * no arguments, and -copies is an option that takes 1 argument, then
    113     * <pre>
    114     *     -print -copies 3
    115     * </pre>
    116     * produces an array of arrays that looks like:
    117     * <pre>
    118     *      option[0][0] = -print
    119     *      option[1][0] = -copies
    120     *      option[1][1] = 3
    121     * </pre>
    122     * (By convention, command line switches start with a "-", but
    123     * they don't have to.)
    124     * <p>
    125     * <b>Note:</b><br>
    126     * Javadoc passes <i>all</i>parameters to this method, not just
    127     * those that Javadoc doesn't recognize. The only way to
    128     * identify unexpected arguments is therefore to check for every
    129     * Javadoc parameter as well as doclet parameters.
    130     *
    131     * @param options   an array of String arrays, one per option
    132     * @param reporter  a DocErrorReporter for generating error messages
    133     * @return true if no errors were found, and all options are
    134     *         valid
    135     */
    136     public static boolean validOptions(String[][] options,
    137                                        DocErrorReporter reporter) {
    138         final DocErrorReporter errOut = reporter;
    139 
    140         // A nice object-oriented way of handling errors. An instance of this
    141         // class puts out an error message and keeps track of whether or not
    142         // an error was found.
    143         class ErrorHandler {
    144             boolean noErrorsFound = true;
    145             void msg(String msg) {
    146                 noErrorsFound = false;
    147                 errOut.printError(msg);
    148             }
    149         }
    150 
    151         ErrorHandler err = new ErrorHandler();
    152         if (trace)
    153             System.out.println("Command line arguments: ");
    154         for (int i = 0; i < options.length; i++) {
    155             for (int j = 0; j < options[i].length; j++) {
    156                 Options.cmdOptions += " " + options[i][j];
    157                 if (trace)
    158                     System.out.print(" " + options[i][j]);
    159             }
    160         }
    161         if (trace)
    162             System.out.println();
    163 
    164         for (int i = 0; i < options.length; i++) {
    165             if (options[i][0].toLowerCase().equals("-apiname")) {
    166                 if (options[i].length < 2) {
    167                     err.msg("No version identifier specified after -apiname option.");
    168                 } else if (JDiff.compareAPIs) {
    169                     err.msg("Use the -apiname option, or the -oldapi and -newapi options, but not both.");
    170                 } else {
    171                     String filename = options[i][1];
    172                     RootDocToXML.apiIdentifier = filename;
    173                     filename = filename.replace(' ', '_');
    174                     RootDocToXML.outputFileName =  filename + ".xml";
    175                     JDiff.writeXML = true;
    176                     JDiff.compareAPIs = false;
    177                 }
    178                 continue;
    179             }
    180             if (options[i][0].toLowerCase().equals("-apidir")) {
    181                 if (options[i].length < 2) {
    182                     err.msg("No directory specified after -apidir option.");
    183                 } else {
    184 		    RootDocToXML.outputDirectory = options[i][1];
    185                 }
    186                 continue;
    187             }
    188 	    if (options[i][0].toLowerCase().equals("-oldapi")) {
    189                 if (options[i].length < 2) {
    190                     err.msg("No version identifier specified after -oldapi option.");
    191                 } else if (JDiff.writeXML) {
    192                     err.msg("Use the -apiname or -oldapi option, but not both.");
    193                 } else {
    194                     String filename = options[i][1];
    195                     filename = filename.replace(' ', '_');
    196                     JDiff.oldFileName =  filename + ".xml";
    197                     JDiff.writeXML = false;
    198                     JDiff.compareAPIs = true;
    199                 }
    200                 continue;
    201             }
    202             if (options[i][0].toLowerCase().equals("-oldapidir")) {
    203                 if (options[i].length < 2) {
    204                     err.msg("No directory specified after -oldapidir option.");
    205                 } else {
    206                 	JDiff.oldDirectory = options[i][1];
    207                 }
    208                 continue;
    209             }
    210             if (options[i][0].toLowerCase().equals("-newapi")) {
    211                 if (options[i].length < 2) {
    212                     err.msg("No version identifier specified after -newapi option.");
    213                 } else if (JDiff.writeXML) {
    214                     err.msg("Use the -apiname or -newapi option, but not both.");
    215                 } else {
    216                     String filename = options[i][1];
    217                     filename = filename.replace(' ', '_');
    218                     JDiff.newFileName =  filename + ".xml";
    219                     JDiff.writeXML = false;
    220                     JDiff.compareAPIs = true;
    221                 }
    222                 continue;
    223             }
    224             if (options[i][0].toLowerCase().equals("-newapidir")) {
    225                 if (options[i].length < 2) {
    226                     err.msg("No directory specified after -newapidir option.");
    227                 } else {
    228                 	JDiff.newDirectory = options[i][1];
    229                 }
    230                 continue;
    231             }
    232             if (options[i][0].toLowerCase().equals("-usercommentsdir")) {
    233                 if (options[i].length < 2) {
    234                     err.msg("Android: No directory specified after -usercommentsdir option.");
    235                 } else {
    236                     HTMLReportGenerator.commentsDir = options[i][1];
    237                 }
    238                 continue;
    239             }
    240             if (options[i][0].toLowerCase().equals("-d")) {
    241                 if (options[i].length < 2) {
    242                     err.msg("No directory specified after -d option.");
    243                 } else {
    244                     HTMLReportGenerator.outputDir = options[i][1];
    245                 }
    246                 continue;
    247             }
    248             if (options[i][0].toLowerCase().equals("-javadocnew")) {
    249                 if (options[i].length < 2) {
    250                     err.msg("No location specified after -javadocnew option.");
    251                 } else {
    252                     HTMLReportGenerator.newDocPrefix = options[i][1];
    253                 }
    254                 continue;
    255             }
    256             if (options[i][0].toLowerCase().equals("-javadocold")) {
    257                 if (options[i].length < 2) {
    258                     err.msg("No location specified after -javadocold option.");
    259                 } else {
    260                     HTMLReportGenerator.oldDocPrefix = options[i][1];
    261                 }
    262                 continue;
    263             }
    264             if (options[i][0].toLowerCase().equals("-baseuri")) {
    265                 if (options[i].length < 2) {
    266                     err.msg("No base location specified after -baseURI option.");
    267                 } else {
    268                     RootDocToXML.baseURI = options[i][1];
    269                 }
    270                 continue;
    271             }
    272             if (options[i][0].toLowerCase().equals("-excludeclass")) {
    273                 if (options[i].length < 2) {
    274                     err.msg("No level (public|protected|package|private) specified after -excludeclass option.");
    275                 } else {
    276                     String level = options[i][1];
    277                     if (level.compareTo("public") != 0 &&
    278                         level.compareTo("protected") != 0 &&
    279                         level.compareTo("package") != 0 &&
    280                         level.compareTo("private") != 0) {
    281                         err.msg("Level specified after -excludeclass option must be one of (public|protected|package|private).");
    282                     } else {
    283                         RootDocToXML.classVisibilityLevel = level;
    284                     }
    285                 }
    286                 continue;
    287             }
    288             if (options[i][0].toLowerCase().equals("-excludemember")) {
    289                 if (options[i].length < 2) {
    290                     err.msg("No level (public|protected|package|private) specified after -excludemember option.");
    291                 } else {
    292                     String level = options[i][1];
    293                     if (level.compareTo("public") != 0 &&
    294                         level.compareTo("protected") != 0 &&
    295                         level.compareTo("package") != 0 &&
    296                         level.compareTo("private") != 0) {
    297                         err.msg("Level specified after -excludemember option must be one of (public|protected|package|private).");
    298                     } else {
    299                         RootDocToXML.memberVisibilityLevel = level;
    300                     }
    301                 }
    302                 continue;
    303             }
    304             if (options[i][0].toLowerCase().equals("-firstsentence")) {
    305                 RootDocToXML.saveAllDocs = false;
    306                 continue;
    307             }
    308             if (options[i][0].toLowerCase().equals("-docchanges")) {
    309                 HTMLReportGenerator.reportDocChanges = true;
    310                 Diff.noDocDiffs = false;
    311                 continue;
    312             }
    313             if (options[i][0].toLowerCase().equals("-packagesonly")) {
    314                 RootDocToXML.packagesOnly = true;
    315                 continue;
    316             }
    317             if (options[i][0].toLowerCase().equals("-showallchanges")) {
    318                 Diff.showAllChanges = true;
    319                 continue;
    320             }
    321             if (options[i][0].toLowerCase().equals("-nosuggest")) {
    322                 if (options[i].length < 2) {
    323                     err.msg("No level (all|remove|add|change) specified after -nosuggest option.");
    324                 } else {
    325                     String level = options[i][1];
    326                     if (level.compareTo("all") != 0 &&
    327                         level.compareTo("remove") != 0 &&
    328                         level.compareTo("add") != 0 &&
    329                         level.compareTo("change") != 0) {
    330                         err.msg("Level specified after -nosuggest option must be one of (all|remove|add|change).");
    331                     } else {
    332                         if (level.compareTo("removal") == 0)
    333                             HTMLReportGenerator.noCommentsOnRemovals = true;
    334                         else if (level.compareTo("add") == 0)
    335                             HTMLReportGenerator.noCommentsOnAdditions = true;
    336                         else if (level.compareTo("change") == 0)
    337                             HTMLReportGenerator.noCommentsOnChanges = true;
    338                         else if (level.compareTo("all") == 0) {
    339                             HTMLReportGenerator.noCommentsOnRemovals = true;
    340                             HTMLReportGenerator.noCommentsOnAdditions = true;
    341                             HTMLReportGenerator.noCommentsOnChanges = true;
    342                         }
    343                     }
    344                 }
    345                 continue;
    346             }
    347             if (options[i][0].toLowerCase().equals("-checkcomments")) {
    348                 APIHandler.checkIsSentence = true;
    349                 continue;
    350             }
    351             if (options[i][0].toLowerCase().equals("-retainnonprinting")) {
    352                 RootDocToXML.stripNonPrintables = false;
    353                 continue;
    354             }
    355             if (options[i][0].toLowerCase().equals("-excludetag")) {
    356                 if (options[i].length < 2) {
    357                     err.msg("No exclude tag specified after -excludetag option.");
    358                 } else {
    359                     RootDocToXML.excludeTag = options[i][1];
    360                     RootDocToXML.excludeTag = RootDocToXML.excludeTag.trim();
    361                     RootDocToXML.doExclude = true;
    362                 }
    363                 continue;
    364             }
    365             if (options[i][0].toLowerCase().equals("-stats")) {
    366                 HTMLReportGenerator.doStats = true;
    367                 continue;
    368             }
    369             if (options[i][0].toLowerCase().equals("-doctitle")) {
    370                 if (options[i].length < 2) {
    371                     err.msg("No HTML text specified after -doctitle option.");
    372                 } else {
    373                     HTMLReportGenerator.docTitle = options[i][1];
    374                 }
    375                 continue;
    376             }
    377             if (options[i][0].toLowerCase().equals("-windowtitle")) {
    378                 if (options[i].length < 2) {
    379                     err.msg("No text specified after -windowtitle option.");
    380                 } else {
    381                     HTMLReportGenerator.windowTitle = options[i][1];
    382                 }
    383                 continue;
    384             }
    385             if (options[i][0].toLowerCase().equals("-version")) {
    386                 System.out.println("JDiff version: " + JDiff.version);
    387                 System.exit(0);
    388             }
    389             if (options[i][0].toLowerCase().equals("-help")) {
    390                 usage();
    391                 System.exit(0);
    392             }
    393         }//for
    394         if (!JDiff.writeXML && !JDiff.compareAPIs) {
    395             err.msg("First use the -apiname option to generate an XML file for one API.");
    396             err.msg("Then use the -apiname option again to generate another XML file for a different version of the API.");
    397             err.msg("Finally use the -oldapi option and -newapi option to generate a report about how the APIs differ.");
    398         }
    399         return err.noErrorsFound;
    400     }// validOptions()
    401 
    402     /** Display the arguments for JDiff. */
    403     public static void usage() {
    404         System.err.println("JDiff version: " + JDiff.version);
    405         System.err.println("");
    406         System.err.println("Valid JDiff arguments:");
    407         System.err.println("");
    408         System.err.println("  -apiname <Name of a version>");
    409         System.err.println("  -oldapi <Name of a version>");
    410         System.err.println("  -newapi <Name of a version>");
    411 
    412         System.err.println("  Optional Arguments");
    413         System.err.println();
    414         System.err.println("  -d <directory> Destination directory for output HTML files");
    415         System.err.println("  -oldapidir <directory> Location of the XML file for the old API");
    416         System.err.println("  -newapidir <directory> Location of the XML file for the new API");
    417         System.err.println("  -sourcepath <location of Java source files>");
    418         System.err.println("  -javadocnew <location of existing Javadoc files for the new API>");
    419         System.err.println("  -javadocold <location of existing Javadoc files for the old API>");
    420         System.err.println("  -usercommentsdir <directory> Path to dir containing the user_comments* file(s)");
    421 
    422         System.err.println("  -baseURI <base> Use \"base\" as the base location of the various DTDs and Schemas used by JDiff");
    423         System.err.println("  -excludeclass [public|protected|package|private] Exclude classes which are not public, protected etc");
    424         System.err.println("  -excludemember [public|protected|package|private] Exclude members which are not public, protected etc");
    425 
    426         System.err.println("  -firstsentence Save only the first sentence of each comment block with the API.");
    427         System.err.println("  -docchanges Report changes in Javadoc comments between the APIs");
    428         System.err.println("  -nosuggest [all|remove|add|change] Do not add suggested comments to all, or the removed, added or chabged sections");
    429         System.err.println("  -checkcomments Check that comments are sentences");
    430         System.err.println("  -stripnonprinting Remove non-printable characters from comments.");
    431         System.err.println("  -excludetag <tag> Define the Javadoc tag which implies exclusion");
    432         System.err.println("  -stats Generate statistical output");
    433         System.err.println("  -help       (generates this output)");
    434         System.err.println("");
    435         System.err.println("For more help, see jdiff.html");
    436     }
    437 
    438     /** All the options passed on the command line. Logged to XML. */
    439     public static String cmdOptions = "";
    440 
    441     /** Set to enable increased logging verbosity for debugging. */
    442     private static boolean trace = false;
    443 }
    444