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 26 package com.sun.tools.sjavac.options; 27 28 import java.io.File; 29 import java.nio.file.Path; 30 import java.nio.file.Paths; 31 import java.util.ArrayList; 32 import java.util.List; 33 import java.util.regex.Matcher; 34 import java.util.regex.Pattern; 35 36 import com.sun.tools.sjavac.CopyFile; 37 import 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 */ 56 public 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 P("-p", "An alias for --module-path") { 89 @Override 90 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 91 MODULE_PATH.processMatching(iter, helper); 92 } 93 }, 94 CLASS_PATH("--class-path", "Specify search path for classes.") { 95 @Override 96 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 97 List<Path> paths = getFileListArg(iter, helper); 98 if (paths != null) 99 helper.classpath(paths); 100 } 101 }, 102 CLASSPATH("-classpath", "An alias for -classpath.") { 103 @Override 104 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 105 CLASS_PATH.processMatching(iter, helper); 106 } 107 }, 108 CP("-cp", "An alias for -classpath") { 109 @Override 110 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 111 CLASS_PATH.processMatching(iter, helper); 112 } 113 }, 114 X("-x", "Exclude files matching the given pattern") { 115 @Override 116 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 117 String pattern = getFilePatternArg(iter, helper); 118 if (pattern != null) 119 helper.exclude(pattern); 120 } 121 }, 122 I("-i", "Include only files matching the given pattern") { 123 @Override 124 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 125 String pattern = getFilePatternArg(iter, helper); 126 if (pattern != null) 127 helper.include(pattern); 128 } 129 }, 130 TR("-tr", "Translate resources") { 131 @Override 132 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 133 134 if (!iter.hasNext()) { 135 helper.reportError(arg + " must be followed by a translation rule"); 136 return; 137 } 138 139 String trArg = iter.next(); 140 141 // Validate argument syntax. Examples: 142 // .prop=com.sun.tools.javac.smart.CompileProperties 143 // .idl=com.sun.corba.CompileIdl 144 // .g3=antlr.CompileGrammar,debug=true 145 String ident = "[a-zA-Z_][a-zA-Z0-9_]*"; 146 Pattern p = Pattern.compile("(?<suffix>\\." + ident + ")=" + 147 "(?<class>" + ident + "(\\." + ident + ")*)" + 148 "(?<extra>,.*)?"); 149 // Check syntax 150 Matcher m = p.matcher(trArg); 151 if (!m.matches()) { 152 helper.reportError("The string \"" + trArg + "\" is not a " + 153 "valid translate pattern"); 154 return; 155 } 156 157 // Extract relevant parts 158 String suffix = m.group("suffix"); 159 String classname = m.group("class"); 160 String extra = m.group("extra"); 161 162 // Valid suffix? 163 if (suffix.matches("\\.(class|java)")) { 164 helper.reportError("You cannot have a translator for " + 165 suffix + " files!"); 166 return; 167 } 168 169 // Construct transformer 170 try { 171 Class<?> trCls = Class.forName(classname); 172 Transformer transformer = 173 (Transformer) trCls.getConstructor().newInstance(); 174 transformer.setExtra(extra); 175 helper.addTransformer(suffix, transformer); 176 } catch (Exception e) { 177 helper.reportError("Cannot use " + classname + 178 " as a translator: " + e.getMessage()); 179 } 180 } 181 }, 182 COPY("-copy", "Copy resources") { 183 @Override 184 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 185 if (!iter.hasNext()) { 186 helper.reportError(arg + " must be followed by a resource type"); 187 return; 188 } 189 190 String copyArg = iter.next(); 191 192 // Validate argument syntax. Examples: .gif, .html 193 if (!copyArg.matches("\\.[a-zA-Z_][a-zA-Z0-9_]*")) { 194 helper.reportError("The string \"" + copyArg + "\" is not a " + 195 "valid resource type."); 196 return; 197 } 198 199 helper.addTransformer(copyArg, new CopyFile()); 200 } 201 }, 202 J("-j", "Number of cores") { 203 @Override 204 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 205 if (!iter.hasNext() || !iter.peek().matches("\\d+")) { 206 helper.reportError(arg + " must be followed by an integer"); 207 return; 208 } 209 helper.numCores(Integer.parseInt(iter.next())); 210 } 211 }, 212 SERVER("--server:", "Specify server configuration file of running server") { 213 @Override 214 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 215 helper.serverConf(iter.current().substring(arg.length())); 216 } 217 }, 218 STARTSERVER("--startserver:", "Start server and use the given configuration file") { 219 @Override 220 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 221 helper.startServerConf(iter.current().substring(arg.length())); 222 } 223 }, 224 IMPLICIT("-implicit:", "Specify how to treat implicitly referenced source code") { 225 @Override 226 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 227 helper.implicit(iter.current().substring(arg.length())); 228 } 229 }, 230 LOG("--log=", "Specify logging level") { 231 @Override 232 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 233 helper.logLevel(iter.current().substring(arg.length())); 234 } 235 }, 236 VERBOSE("-verbose", "Set verbosity level to \"info\"") { 237 @Override 238 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 239 helper.logLevel("info"); 240 } 241 }, 242 PERMIT_ARTIFACT("--permit-artifact=", "Allow this artifact in destination directory") { 243 @Override 244 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 245 String a = iter.current().substring(arg.length()); 246 helper.permitArtifact(Paths.get(a).toFile().getAbsolutePath()); 247 } 248 }, 249 PERMIT_UNIDENTIFIED_ARTIFACTS("--permit-unidentified-artifacts", "Allow unidentified artifacts in destination directory") { 250 @Override 251 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 252 helper.permitUnidentifiedArtifacts(); 253 } 254 }, 255 PERMIT_SOURCES_WITHOUT_PACKAGE("--permit-sources-without-package", "Permit sources in the default package") { 256 @Override 257 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 258 helper.permitDefaultPackage(); 259 } 260 }, 261 COMPARE_FOUND_SOURCES("--compare-found-sources", "Compare found sources with given sources") { 262 @Override 263 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 264 Path referenceSourceList = getFileArg(iter, helper, true, false); 265 if (referenceSourceList != null) 266 helper.compareFoundSources(referenceSourceList); 267 } 268 }, 269 D("-d", "Output destination directory") { 270 @Override 271 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 272 Path dir = getFileArg(iter, helper, false, true); 273 if (dir != null) 274 helper.destDir(dir); 275 } 276 }, 277 S("-s", "Directory for generated sources") { 278 @Override 279 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 280 Path dir = getFileArg(iter, helper, false, true); 281 if (dir != null) 282 helper.generatedSourcesDir(dir); 283 } 284 }, 285 H("-h", "Directory for header files") { 286 @Override 287 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 288 Path dir = getFileArg(iter, helper, false, true); 289 if (dir != null) 290 helper.headerDir(dir); 291 } 292 }, 293 STATE_DIR("--state-dir=", "Directory used to store sjavac state and log files.") { 294 @Override 295 protected void processMatching(ArgumentIterator iter, OptionHelper helper) { 296 String p = iter.current().substring(arg.length()); 297 helper.stateDir(Paths.get(p)); 298 } 299 }; 300 301 302 public final String arg; 303 304 final String description; 305 306 private Option(String arg, String description) { 307 this.arg = arg; 308 this.description = description; 309 } 310 311 /** Retrieve and verify syntax of file list argument. */ 312 List<Path> getFileListArg(ArgumentIterator iter, OptionHelper helper) { 313 if (!iter.hasNext()) { 314 helper.reportError(arg + " must be followed by a list of files " + 315 "separated by " + File.pathSeparator); 316 return null; 317 } 318 List<Path> result = new ArrayList<>(); 319 for (String pathStr : iter.next().split(File.pathSeparator)) 320 result.add(Paths.get(pathStr)); 321 return result; 322 } 323 324 /** Retrieve and verify syntax of file argument. */ 325 Path getFileArg(ArgumentIterator iter, OptionHelper helper, boolean fileAcceptable, boolean dirAcceptable) { 326 327 if (!iter.hasNext()) { 328 String errmsg = arg + " must be followed by "; 329 if (fileAcceptable && dirAcceptable) errmsg += "a file or directory."; 330 else if (fileAcceptable) errmsg += "a file."; 331 else if (dirAcceptable) errmsg += "a directory."; 332 else throw new IllegalArgumentException("File or directory must be acceptable."); 333 helper.reportError(errmsg); 334 return null; 335 } 336 337 return Paths.get(iter.next()); 338 } 339 340 /** Retrieve the next file or package argument. */ 341 String getFilePatternArg(ArgumentIterator iter, OptionHelper helper) { 342 343 if (!iter.hasNext()) { 344 helper.reportError(arg + " must be followed by a glob pattern."); 345 return null; 346 } 347 348 return iter.next(); 349 } 350 351 // Future cleanup: Change the "=" syntax to ":" syntax to be consistent and 352 // to follow the javac-option style. 353 354 public boolean hasOption() { 355 return arg.endsWith(":") || arg.endsWith("="); 356 } 357 358 359 /** 360 * Process current argument of argIter. 361 * 362 * It's final, since the option customization is typically done in 363 * processMatching. 364 * 365 * @param argIter Iterator to read current and succeeding arguments from. 366 * @param helper The helper to report back to. 367 * @return true iff the argument was processed by this option. 368 */ 369 public final boolean processCurrent(ArgumentIterator argIter, 370 OptionHelper helper) { 371 String fullArg = argIter.current(); // "-tr" or "-log=level" 372 if (hasOption() ? fullArg.startsWith(arg) : fullArg.equals(arg)) { 373 processMatching(argIter, helper); 374 return true; 375 } 376 // Did not match 377 return false; 378 } 379 380 /** Called by process if the current argument matches this option. */ 381 protected abstract void processMatching(ArgumentIterator argIter, 382 OptionHelper helper); 383 }