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