Option.java revision 3573:c4a18ee691c4
1/* 2 * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.tools.sjavac.options; 27 28import java.io.File; 29import java.nio.file.Path; 30import java.nio.file.Paths; 31import java.util.ArrayList; 32import java.util.List; 33import java.util.regex.Matcher; 34import java.util.regex.Pattern; 35 36import com.sun.tools.sjavac.CopyFile; 37import com.sun.tools.sjavac.Transformer; 38 39 40/** 41 * Sjavac options can be classified as: 42 * 43 * (1) relevant only for sjavac, such as --server 44 * (2) relevant for sjavac and javac, such as -d, or 45 * (3) relevant only for javac, such as -g. 46 * 47 * This enum represents all options from (1) and (2). Note that instances of 48 * this enum only entail static information about the option. For storage of 49 * option values, refer to com.sun.tools.sjavac.options.Options. 50 * 51 * <p><b>This is NOT part of any supported API. 52 * If you write code that depends on this, you do so at your own risk. 53 * This code and its internal interfaces are subject to change or 54 * deletion without notice.</b> 55 */ 56public enum Option { 57 58 SRC("-src", "Location of source files to be compiled") { 59 @Override 60 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 61 List<Path> paths = getFileListArg(iter, helper); 62 if (paths != null) 63 helper.sourceRoots(paths); 64 } 65 }, 66 SOURCE_PATH("--source-path", "Specify search path for sources.") { 67 @Override 68 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 69 List<Path> paths = getFileListArg(iter, helper); 70 if (paths != null) 71 helper.sourcepath(paths); 72 } 73 }, 74 SOURCEPATH("-sourcepath", "An alias for -sourcepath") { 75 @Override 76 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 77 SOURCE_PATH.processMatching(iter, helper); 78 } 79 }, 80 MODULE_PATH("--module-path", "Specify search path for modules.") { 81 @Override 82 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 83 List<Path> paths = getFileListArg(iter, helper); 84 if (paths != null) 85 helper.modulepath(paths); 86 } 87 }, 88 MODULEPATH("-modulepath", "An alias for -modulepath") { 89 @Override 90 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 91 MODULE_PATH.processMatching(iter, helper); 92 } 93 }, 94 P("-p", "An alias for -modulepath") { 95 @Override 96 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 97 MODULE_PATH.processMatching(iter, helper); 98 } 99 }, 100 CLASS_PATH("--class-path", "Specify search path for classes.") { 101 @Override 102 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 103 List<Path> paths = getFileListArg(iter, helper); 104 if (paths != null) 105 helper.classpath(paths); 106 } 107 }, 108 CLASSPATH("-classpath", "An alias for -classpath.") { 109 @Override 110 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 111 CLASS_PATH.processMatching(iter, helper); 112 } 113 }, 114 CP("-cp", "An alias for -classpath") { 115 @Override 116 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 117 CLASS_PATH.processMatching(iter, helper); 118 } 119 }, 120 X("-x", "Exclude files matching the given pattern") { 121 @Override 122 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 123 String pattern = getFilePatternArg(iter, helper); 124 if (pattern != null) 125 helper.exclude(pattern); 126 } 127 }, 128 I("-i", "Include only files matching the given pattern") { 129 @Override 130 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 131 String pattern = getFilePatternArg(iter, helper); 132 if (pattern != null) 133 helper.include(pattern); 134 } 135 }, 136 TR("-tr", "Translate resources") { 137 @Override 138 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 139 140 if (!iter.hasNext()) { 141 helper.reportError(arg + " must be followed by a translation rule"); 142 return; 143 } 144 145 String trArg = iter.next(); 146 147 // Validate argument syntax. Examples: 148 // .prop=com.sun.tools.javac.smart.CompileProperties 149 // .idl=com.sun.corba.CompileIdl 150 // .g3=antlr.CompileGrammar,debug=true 151 String ident = "[a-zA-Z_][a-zA-Z0-9_]*"; 152 Pattern p = Pattern.compile("(?<suffix>\\." + ident + ")=" + 153 "(?<class>" + ident + "(\\." + ident + ")*)" + 154 "(?<extra>,.*)?"); 155 // Check syntax 156 Matcher m = p.matcher(trArg); 157 if (!m.matches()) { 158 helper.reportError("The string \"" + trArg + "\" is not a " + 159 "valid translate pattern"); 160 return; 161 } 162 163 // Extract relevant parts 164 String suffix = m.group("suffix"); 165 String classname = m.group("class"); 166 String extra = m.group("extra"); 167 168 // Valid suffix? 169 if (suffix.matches("\\.(class|java)")) { 170 helper.reportError("You cannot have a translator for " + 171 suffix + " files!"); 172 return; 173 } 174 175 // Construct transformer 176 try { 177 Class<?> trCls = Class.forName(classname); 178 Transformer transformer = 179 (Transformer) trCls.getConstructor().newInstance(); 180 transformer.setExtra(extra); 181 helper.addTransformer(suffix, transformer); 182 } catch (Exception e) { 183 helper.reportError("Cannot use " + classname + 184 " as a translator: " + e.getMessage()); 185 } 186 } 187 }, 188 COPY("-copy", "Copy resources") { 189 @Override 190 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 191 if (!iter.hasNext()) { 192 helper.reportError(arg + " must be followed by a resource type"); 193 return; 194 } 195 196 String copyArg = iter.next(); 197 198 // Validate argument syntax. Examples: .gif, .html 199 if (!copyArg.matches("\\.[a-zA-Z_][a-zA-Z0-9_]*")) { 200 helper.reportError("The string \"" + copyArg + "\" is not a " + 201 "valid resource type."); 202 return; 203 } 204 205 helper.addTransformer(copyArg, new CopyFile()); 206 } 207 }, 208 J("-j", "Number of cores") { 209 @Override 210 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 211 if (!iter.hasNext() || !iter.peek().matches("\\d+")) { 212 helper.reportError(arg + " must be followed by an integer"); 213 return; 214 } 215 helper.numCores(Integer.parseInt(iter.next())); 216 } 217 }, 218 SERVER("--server:", "Specify server configuration file of running server") { 219 @Override 220 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 221 helper.serverConf(iter.current().substring(arg.length())); 222 } 223 }, 224 STARTSERVER("--startserver:", "Start server and use the given configuration file") { 225 @Override 226 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 227 helper.startServerConf(iter.current().substring(arg.length())); 228 } 229 }, 230 IMPLICIT("-implicit:", "Specify how to treat implicitly referenced source code") { 231 @Override 232 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 233 helper.implicit(iter.current().substring(arg.length())); 234 } 235 }, 236 LOG("--log=", "Specify logging level") { 237 @Override 238 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 239 helper.logLevel(iter.current().substring(arg.length())); 240 } 241 }, 242 VERBOSE("-verbose", "Set verbosity level to \"info\"") { 243 @Override 244 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 245 helper.logLevel("info"); 246 } 247 }, 248 PERMIT_ARTIFACT("--permit-artifact=", "Allow this artifact in destination directory") { 249 @Override 250 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 251 String a = iter.current().substring(arg.length()); 252 helper.permitArtifact(Paths.get(a).toFile().getAbsolutePath()); 253 } 254 }, 255 PERMIT_UNIDENTIFIED_ARTIFACTS("--permit-unidentified-artifacts", "Allow unidentified artifacts in destination directory") { 256 @Override 257 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 258 helper.permitUnidentifiedArtifacts(); 259 } 260 }, 261 PERMIT_SOURCES_WITHOUT_PACKAGE("--permit-sources-without-package", "Permit sources in the default package") { 262 @Override 263 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 264 helper.permitDefaultPackage(); 265 } 266 }, 267 COMPARE_FOUND_SOURCES("--compare-found-sources", "Compare found sources with given sources") { 268 @Override 269 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 270 Path referenceSourceList = getFileArg(iter, helper, true, false); 271 if (referenceSourceList != null) 272 helper.compareFoundSources(referenceSourceList); 273 } 274 }, 275 D("-d", "Output destination directory") { 276 @Override 277 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 278 Path dir = getFileArg(iter, helper, false, true); 279 if (dir != null) 280 helper.destDir(dir); 281 } 282 }, 283 S("-s", "Directory for generated sources") { 284 @Override 285 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 286 Path dir = getFileArg(iter, helper, false, true); 287 if (dir != null) 288 helper.generatedSourcesDir(dir); 289 } 290 }, 291 H("-h", "Directory for header files") { 292 @Override 293 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 294 Path dir = getFileArg(iter, helper, false, true); 295 if (dir != null) 296 helper.headerDir(dir); 297 } 298 }, 299 STATE_DIR("--state-dir=", "Directory used to store sjavac state and log files.") { 300 @Override 301 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 302 String p = iter.current().substring(arg.length()); 303 helper.stateDir(Paths.get(p)); 304 } 305 }; 306 307 308 public final String arg; 309 310 final String description; 311 312 private Option(String arg, String description) { 313 this.arg = arg; 314 this.description = description; 315 } 316 317 /** Retrieve and verify syntax of file list argument. */ 318 List<Path> getFileListArg(ArgumentIterator iter, OptionHelper helper) { 319 if (!iter.hasNext()) { 320 helper.reportError(arg + " must be followed by a list of files " + 321 "separated by " + File.pathSeparator); 322 return null; 323 } 324 List<Path> result = new ArrayList<>(); 325 for (String pathStr : iter.next().split(File.pathSeparator)) 326 result.add(Paths.get(pathStr)); 327 return result; 328 } 329 330 /** Retrieve and verify syntax of file argument. */ 331 Path getFileArg(ArgumentIterator iter, OptionHelper helper, boolean fileAcceptable, boolean dirAcceptable) { 332 333 if (!iter.hasNext()) { 334 String errmsg = arg + " must be followed by "; 335 if (fileAcceptable && dirAcceptable) errmsg += "a file or directory."; 336 else if (fileAcceptable) errmsg += "a file."; 337 else if (dirAcceptable) errmsg += "a directory."; 338 else throw new IllegalArgumentException("File or directory must be acceptable."); 339 helper.reportError(errmsg); 340 return null; 341 } 342 343 return Paths.get(iter.next()); 344 } 345 346 /** Retrieve the next file or package argument. */ 347 String getFilePatternArg(ArgumentIterator iter, OptionHelper helper) { 348 349 if (!iter.hasNext()) { 350 helper.reportError(arg + " must be followed by a glob pattern."); 351 return null; 352 } 353 354 return iter.next(); 355 } 356 357 // Future cleanup: Change the "=" syntax to ":" syntax to be consistent and 358 // to follow the javac-option style. 359 360 public boolean hasOption() { 361 return arg.endsWith(":") || arg.endsWith("="); 362 } 363 364 365 /** 366 * Process current argument of argIter. 367 * 368 * It's final, since the option customization is typically done in 369 * processMatching. 370 * 371 * @param argIter Iterator to read current and succeeding arguments from. 372 * @param helper The helper to report back to. 373 * @return true iff the argument was processed by this option. 374 */ 375 public final boolean processCurrent(ArgumentIterator argIter, 376 OptionHelper helper) { 377 String fullArg = argIter.current(); // "-tr" or "-log=level" 378 if (hasOption() ? fullArg.startsWith(arg) : fullArg.equals(arg)) { 379 processMatching(argIter, helper); 380 return true; 381 } 382 // Did not match 383 return false; 384 } 385 386 /** Called by process if the current argument matches this option. */ 387 protected abstract void processMatching(ArgumentIterator argIter, 388 OptionHelper helper); 389} 390