Option.java revision 2593:035b01d356ee
11573Srgrimes/* 21573Srgrimes * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 31573Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41573Srgrimes * 51573Srgrimes * This code is free software; you can redistribute it and/or modify it 61573Srgrimes * under the terms of the GNU General Public License version 2 only, as 71573Srgrimes * published by the Free Software Foundation. Oracle designates this 81573Srgrimes * particular file as subject to the "Classpath" exception as provided 91573Srgrimes * by Oracle in the LICENSE file that accompanied this code. 101573Srgrimes * 111573Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 121573Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131573Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141573Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 151573Srgrimes * accompanied this code). 161573Srgrimes * 171573Srgrimes * You should have received a copy of the GNU General Public License version 181573Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 191573Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 201573Srgrimes * 211573Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 221573Srgrimes * or visit www.oracle.com if you need additional information or have any 231573Srgrimes * questions. 241573Srgrimes */ 251573Srgrimes 261573Srgrimespackage com.sun.tools.sjavac.options; 271573Srgrimes 281573Srgrimesimport java.io.File; 291573Srgrimesimport java.nio.file.Path; 301573Srgrimesimport java.nio.file.Paths; 311573Srgrimesimport java.util.ArrayList; 321573Srgrimesimport java.util.List; 331573Srgrimesimport java.util.regex.Matcher; 341573Srgrimesimport java.util.regex.Pattern; 351573Srgrimes 361573Srgrimesimport com.sun.tools.sjavac.CopyFile; 371573Srgrimesimport com.sun.tools.sjavac.Transformer; 381573Srgrimes 391573Srgrimes 401573Srgrimes/** 411573Srgrimes * Sjavac options can be classified as: 421573Srgrimes * 431573Srgrimes * (1) relevant only for sjavac, such as --server 441573Srgrimes * (2) relevant for sjavac and javac, such as -d, or 451573Srgrimes * (3) relevant only for javac, such as -g. 461573Srgrimes * 471573Srgrimes * This enum represents all options from (1) and (2). Note that instances of 481573Srgrimes * this enum only entail static information about the option. For storage of 4911659Sphk * option values, refer to com.sun.tools.sjavac.options.Options. 501573Srgrimes * 511573Srgrimes * <p><b>This is NOT part of any supported API. 521573Srgrimes * If you write code that depends on this, you do so at your own risk. 531573Srgrimes * This code and its internal interfaces are subject to change or 541573Srgrimes * deletion without notice.</b> 551573Srgrimes */ 561573Srgrimespublic enum Option { 571573Srgrimes 581573Srgrimes SRC("-src", "Location of source files to be compiled") { 591573Srgrimes @Override 601573Srgrimes protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 611573Srgrimes List<Path> paths = getFileListArg(iter, helper); 621573Srgrimes if (paths != null) 631573Srgrimes helper.sourceRoots(paths); 641573Srgrimes } 651573Srgrimes }, 661573Srgrimes SOURCEPATH("-sourcepath", "Specify search path for sources.") { 671573Srgrimes @Override 681573Srgrimes protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 691573Srgrimes List<Path> paths = getFileListArg(iter, helper); 701573Srgrimes if (paths != null) 711573Srgrimes helper.sourcepath(paths); 721573Srgrimes } 731573Srgrimes }, 741573Srgrimes MODULEPATH("-modulepath", "Specify search path for modules.") { 751573Srgrimes @Override 761573Srgrimes protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 771573Srgrimes List<Path> paths = getFileListArg(iter, helper); 781573Srgrimes if (paths != null) 791573Srgrimes helper.modulepath(paths); 801573Srgrimes } 811573Srgrimes }, 821573Srgrimes CLASSPATH("-classpath", "Specify search path for classes.") { 831573Srgrimes @Override 841573Srgrimes protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 851573Srgrimes List<Path> paths = getFileListArg(iter, helper); 861573Srgrimes if (paths != null) 871573Srgrimes helper.classpath(paths); 881573Srgrimes } 891573Srgrimes }, 901573Srgrimes CP("-cp", "An alias for -classpath") { 911573Srgrimes @Override 921573Srgrimes protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 931573Srgrimes CLASSPATH.processMatching(iter, helper); 941573Srgrimes } 951573Srgrimes }, 961573Srgrimes X("-x", "Exclude directory from the subsequent source directory") { 971573Srgrimes @Override 981573Srgrimes protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 991573Srgrimes String pattern = getFilePatternArg(iter, helper); 1001573Srgrimes if (pattern != null) 1011573Srgrimes helper.exclude(pattern); 1021573Srgrimes } 1031573Srgrimes }, 1041573Srgrimes I("-i", "Include only the given directory from the subsequent source directory") { 1051573Srgrimes @Override 1061573Srgrimes protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 1071573Srgrimes String pattern = getFilePatternArg(iter, helper); 1081573Srgrimes if (pattern != null) 1091573Srgrimes helper.include(pattern); 1101573Srgrimes } 1111573Srgrimes }, 1121573Srgrimes XF("-xf", "Exclude a given file") { 1131573Srgrimes @Override 1141573Srgrimes protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 1151573Srgrimes String pattern = getFilePatternArg(iter, helper); 1161573Srgrimes if (pattern != null) 1171573Srgrimes helper.excludeFile(pattern); 1181573Srgrimes } 1191573Srgrimes }, 1201573Srgrimes IF("-if", "Include only the given file") { 1211573Srgrimes @Override 1221573Srgrimes protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 1231573Srgrimes String pattern = getFilePatternArg(iter, helper); 1241573Srgrimes if (pattern != null) 1251573Srgrimes helper.includeFile(pattern); 1261573Srgrimes } 1271573Srgrimes }, 1281573Srgrimes TR("-tr", "Translate resources") { 1291573Srgrimes @Override 1301573Srgrimes protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 1311573Srgrimes 1321573Srgrimes if (!iter.hasNext()) { 1331573Srgrimes helper.reportError(arg + " must be followed by a translation rule"); 1341573Srgrimes return; 1351573Srgrimes } 1361573Srgrimes 1371573Srgrimes String trArg = iter.next(); 1381573Srgrimes 1391573Srgrimes // Validate argument syntax. Examples: 1401573Srgrimes // .prop=com.sun.tools.javac.smart.CompileProperties 1411573Srgrimes // .idl=com.sun.corba.CompileIdl 1421573Srgrimes // .g3=antlr.CompileGrammar,debug=true 1431573Srgrimes String ident = "[a-zA-Z_][a-zA-Z0-9_]*"; 1441573Srgrimes Pattern p = Pattern.compile("(?<suffix>\\." + ident + ")=" + 1451573Srgrimes "(?<class>" + ident + "(\\." + ident + ")*)" + 1461573Srgrimes "(?<extra>,.*)?"); 1471573Srgrimes // Check syntax 1481573Srgrimes Matcher m = p.matcher(trArg); 1491573Srgrimes if (!m.matches()) { 1501573Srgrimes helper.reportError("The string \"" + trArg + "\" is not a " + 1511573Srgrimes "valid translate pattern"); 1521573Srgrimes return; 1531573Srgrimes } 1541573Srgrimes 1551573Srgrimes // Extract relevant parts 1561573Srgrimes String suffix = m.group("suffix"); 1571573Srgrimes String classname = m.group("class"); 1581573Srgrimes String extra = m.group("extra"); 1591573Srgrimes 1601573Srgrimes // Valid suffix? 1611573Srgrimes if (suffix.matches("\\.(class|java)")) { 1621573Srgrimes helper.reportError("You cannot have a translator for " + 1631573Srgrimes suffix + " files!"); 1641573Srgrimes return; 1651573Srgrimes } 1661573Srgrimes 1671573Srgrimes // Construct transformer 1681573Srgrimes try { 1691573Srgrimes Class<?> trCls = Class.forName(classname); 170 Transformer transformer = (Transformer) trCls.newInstance(); 171 transformer.setExtra(extra); 172 helper.addTransformer(suffix, transformer); 173 } catch (Exception e) { 174 helper.reportError("Cannot use " + classname + 175 " as a translator: " + e.getMessage()); 176 } 177 } 178 }, 179 COPY("-copy", "Copy resources") { 180 @Override 181 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 182 if (!iter.hasNext()) { 183 helper.reportError(arg + " must be followed by a resource type"); 184 return; 185 } 186 187 String copyArg = iter.next(); 188 189 // Validate argument syntax. Examples: .gif, .html 190 if (!copyArg.matches("\\.[a-zA-Z_][a-zA-Z0-9_]*")) { 191 helper.reportError("The string \"" + copyArg + "\" is not a " + 192 "valid resource type."); 193 return; 194 } 195 196 helper.addTransformer(copyArg, new CopyFile()); 197 } 198 }, 199 J("-j", "Number of cores") { 200 @Override 201 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 202 if (!iter.hasNext() || !iter.peek().matches("\\d+")) { 203 helper.reportError(arg + " must be followed by an integer"); 204 return; 205 } 206 helper.numCores(Integer.parseInt(iter.next())); 207 } 208 }, 209 SERVER("--server:", "Specify server configuration file of running server") { 210 @Override 211 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 212 helper.serverConf(iter.current().substring(arg.length())); 213 } 214 }, 215 STARTSERVER("--startserver:", "Start server and use the given configuration file") { 216 @Override 217 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 218 helper.startServerConf(iter.current().substring(arg.length())); 219 } 220 }, 221 IMPLICIT("-implicit:", "Specify how to treat implicitly referenced source code") { 222 @Override 223 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 224 helper.implicit(iter.current().substring(arg.length())); 225 } 226 }, 227 LOG("--log=", "Specify logging level") { 228 @Override 229 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 230 helper.logLevel(iter.current().substring(arg.length())); 231 } 232 }, 233 VERBOSE("-verbose", "Set verbosity level to \"info\"") { 234 @Override 235 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 236 helper.logLevel("info"); 237 } 238 }, 239 PERMIT_ARTIFACT("--permit-artifact=", "Allow this artifact in destination directory") { 240 @Override 241 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 242 String a = iter.current().substring(arg.length()); 243 helper.permitArtifact(Paths.get(a).toFile().getAbsolutePath()); 244 } 245 }, 246 PERMIT_UNIDENTIFIED_ARTIFACTS("--permit-unidentified-artifacts", "Allow unidentified artifacts in destination directory") { 247 @Override 248 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 249 helper.permitUnidentifiedArtifacts(); 250 } 251 }, 252 PERMIT_SOURCES_WITHOUT_PACKAGE("--permit-sources-without-package", "Permit sources in the default package") { 253 @Override 254 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 255 helper.permitDefaultPackage(); 256 } 257 }, 258 COMPARE_FOUND_SOURCES("--compare-found-sources", "Compare found sources with given sources") { 259 @Override 260 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 261 Path referenceSourceList = getFileArg(iter, helper, true, false); 262 if (referenceSourceList != null) 263 helper.compareFoundSources(referenceSourceList); 264 } 265 }, 266 D("-d", "Output destination directory") { 267 @Override 268 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 269 Path dir = getFileArg(iter, helper, false, true); 270 if (dir != null) 271 helper.destDir(dir); 272 } 273 }, 274 S("-s", "Directory for generated sources") { 275 @Override 276 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 277 Path dir = getFileArg(iter, helper, false, true); 278 if (dir != null) 279 helper.generatedSourcesDir(dir); 280 } 281 }, 282 H("-h", "Directory for header files") { 283 @Override 284 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 285 Path dir = getFileArg(iter, helper, false, true); 286 if (dir != null) 287 helper.headerDir(dir); 288 } 289 }, 290 STATE_DIR("--state-dir=", "Directory used to store sjavac state and log files.") { 291 @Override 292 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 293 String p = iter.current().substring(arg.length()); 294 helper.stateDir(Paths.get(p)); 295 } 296 }; 297 298 299 public final String arg; 300 301 final String description; 302 303 private Option(String arg, String description) { 304 this.arg = arg; 305 this.description = description; 306 } 307 308 /** Retrieve and verify syntax of file list argument. */ 309 List<Path> getFileListArg(ArgumentIterator iter, OptionHelper helper) { 310 if (!iter.hasNext()) { 311 helper.reportError(arg + " must be followed by a list of files " + 312 "separated by " + File.pathSeparator); 313 return null; 314 } 315 List<Path> result = new ArrayList<>(); 316 for (String pathStr : iter.next().split(File.pathSeparator)) 317 result.add(Paths.get(pathStr)); 318 return result; 319 } 320 321 /** Retrieve and verify syntax of file argument. */ 322 Path getFileArg(ArgumentIterator iter, OptionHelper helper, boolean fileAcceptable, boolean dirAcceptable) { 323 324 if (!iter.hasNext()) { 325 String errmsg = arg + " must be followed by "; 326 if (fileAcceptable && dirAcceptable) errmsg += "a file or directory."; 327 else if (fileAcceptable) errmsg += "a file."; 328 else if (dirAcceptable) errmsg += "a directory."; 329 else throw new IllegalArgumentException("File or directory must be acceptable."); 330 helper.reportError(errmsg); 331 return null; 332 } 333 334 return Paths.get(iter.next()); 335 } 336 337 /** Retrieve the next file or package argument. */ 338 String getFilePatternArg(ArgumentIterator iter, OptionHelper helper) { 339 340 if (!iter.hasNext()) { 341 helper.reportError(arg + " must be followed by a file or directory pattern."); 342 return null; 343 } 344 345 return iter.next(); 346 } 347 348 // Future cleanup: Change the "=" syntax to ":" syntax to be consistent and 349 // to follow the javac-option style. 350 351 public boolean hasOption() { 352 return arg.endsWith(":") || arg.endsWith("="); 353 } 354 355 356 /** 357 * Process current argument of argIter. 358 * 359 * It's final, since the option customization is typically done in 360 * processMatching. 361 * 362 * @param argIter Iterator to read current and succeeding arguments from. 363 * @param helper The helper to report back to. 364 * @return true iff the argument was processed by this option. 365 */ 366 public final boolean processCurrent(ArgumentIterator argIter, 367 OptionHelper helper) { 368 String fullArg = argIter.current(); // "-tr" or "-log=level" 369 if (hasOption() ? fullArg.startsWith(arg) : fullArg.equals(arg)) { 370 processMatching(argIter, helper); 371 return true; 372 } 373 // Did not match 374 return false; 375 } 376 377 /** Called by process if the current argument matches this option. */ 378 protected abstract void processMatching(ArgumentIterator argIter, 379 OptionHelper helper); 380} 381