Mon, 04 Aug 2008 17:54:15 -0700
4884240: additional option required for javap
Reviewed-by: ksrini
jjg@46 | 1 | /* |
xdono@54 | 2 | * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
jjg@46 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
jjg@46 | 4 | * |
jjg@46 | 5 | * This code is free software; you can redistribute it and/or modify it |
jjg@46 | 6 | * under the terms of the GNU General Public License version 2 only, as |
jjg@46 | 7 | * published by the Free Software Foundation. Sun designates this |
jjg@46 | 8 | * particular file as subject to the "Classpath" exception as provided |
jjg@46 | 9 | * by Sun in the LICENSE file that accompanied this code. |
jjg@46 | 10 | * |
jjg@46 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
jjg@46 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
jjg@46 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
jjg@46 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
jjg@46 | 15 | * accompanied this code). |
jjg@46 | 16 | * |
jjg@46 | 17 | * You should have received a copy of the GNU General Public License version |
jjg@46 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
jjg@46 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-15301 USA. |
jjg@46 | 20 | * |
jjg@46 | 21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
jjg@46 | 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
jjg@46 | 23 | * have any questions. |
jjg@46 | 24 | */ |
jjg@46 | 25 | |
jjg@46 | 26 | package com.sun.tools.javap; |
jjg@46 | 27 | |
jjg@46 | 28 | import java.io.EOFException; |
jjg@46 | 29 | import java.io.FileNotFoundException; |
jjg@88 | 30 | import java.io.FilterInputStream; |
jjg@88 | 31 | import java.io.InputStream; |
jjg@46 | 32 | import java.io.IOException; |
jjg@46 | 33 | import java.io.OutputStream; |
jjg@46 | 34 | import java.io.PrintWriter; |
jjg@46 | 35 | import java.io.StringWriter; |
jjg@46 | 36 | import java.io.Writer; |
jjg@88 | 37 | import java.security.DigestInputStream; |
jjg@88 | 38 | import java.security.MessageDigest; |
jjg@46 | 39 | import java.text.MessageFormat; |
jjg@46 | 40 | import java.util.ArrayList; |
jjg@46 | 41 | import java.util.Arrays; |
jjg@46 | 42 | import java.util.HashMap; |
jjg@46 | 43 | import java.util.Iterator; |
jjg@46 | 44 | import java.util.List; |
jjg@46 | 45 | import java.util.Locale; |
jjg@46 | 46 | import java.util.Map; |
jjg@46 | 47 | import java.util.MissingResourceException; |
jjg@46 | 48 | import java.util.ResourceBundle; |
jjg@46 | 49 | |
jjg@46 | 50 | import javax.tools.Diagnostic; |
jjg@46 | 51 | import javax.tools.DiagnosticListener; |
jjg@46 | 52 | import javax.tools.JavaFileManager; |
jjg@46 | 53 | import javax.tools.JavaFileObject; |
jjg@46 | 54 | import javax.tools.StandardJavaFileManager; |
jjg@46 | 55 | import javax.tools.StandardLocation; |
jjg@46 | 56 | |
jjg@46 | 57 | import com.sun.tools.classfile.*; |
jjg@46 | 58 | |
jjg@46 | 59 | /** |
jjg@46 | 60 | * "Main" class for javap, normally accessed from the command line |
jjg@46 | 61 | * via Main, or from JSR199 via DisassemblerTool. |
jjg@46 | 62 | * |
jjg@46 | 63 | * <p><b>This is NOT part of any API supported by Sun Microsystems. If |
jjg@46 | 64 | * you write code that depends on this, you do so at your own risk. |
jjg@46 | 65 | * This code and its internal interfaces are subject to change or |
jjg@46 | 66 | * deletion without notice.</b> |
jjg@46 | 67 | */ |
jjg@46 | 68 | public class JavapTask implements DisassemblerTool.DisassemblerTask { |
jjg@46 | 69 | public class BadArgs extends Exception { |
jjg@46 | 70 | static final long serialVersionUID = 8765093759964640721L; |
jjg@46 | 71 | BadArgs(String key, Object... args) { |
jjg@46 | 72 | super(JavapTask.this.getMessage(key, args)); |
jjg@46 | 73 | this.key = key; |
jjg@46 | 74 | this.args = args; |
jjg@46 | 75 | } |
jjg@46 | 76 | |
jjg@46 | 77 | BadArgs showUsage(boolean b) { |
jjg@46 | 78 | showUsage = b; |
jjg@46 | 79 | return this; |
jjg@46 | 80 | } |
jjg@46 | 81 | |
jjg@46 | 82 | final String key; |
jjg@46 | 83 | final Object[] args; |
jjg@46 | 84 | boolean showUsage; |
jjg@46 | 85 | } |
jjg@46 | 86 | |
jjg@46 | 87 | static abstract class Option { |
jjg@46 | 88 | Option(boolean hasArg, String... aliases) { |
jjg@46 | 89 | this.hasArg = hasArg; |
jjg@46 | 90 | this.aliases = aliases; |
jjg@46 | 91 | } |
jjg@46 | 92 | |
jjg@46 | 93 | boolean matches(String opt) { |
jjg@46 | 94 | for (String a: aliases) { |
jjg@46 | 95 | if (a.equals(opt)) |
jjg@46 | 96 | return true; |
jjg@46 | 97 | } |
jjg@46 | 98 | return false; |
jjg@46 | 99 | } |
jjg@46 | 100 | |
jjg@46 | 101 | boolean ignoreRest() { |
jjg@46 | 102 | return false; |
jjg@46 | 103 | } |
jjg@46 | 104 | |
jjg@46 | 105 | abstract void process(JavapTask task, String opt, String arg) throws BadArgs; |
jjg@46 | 106 | |
jjg@46 | 107 | final boolean hasArg; |
jjg@46 | 108 | final String[] aliases; |
jjg@46 | 109 | } |
jjg@46 | 110 | |
jjg@46 | 111 | static Option[] recognizedOptions = { |
jjg@46 | 112 | |
jjg@46 | 113 | new Option(false, "-help", "--help", "-?") { |
jjg@46 | 114 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 115 | task.options.help = true; |
jjg@46 | 116 | } |
jjg@46 | 117 | }, |
jjg@46 | 118 | |
jjg@46 | 119 | new Option(false, "-version") { |
jjg@46 | 120 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 121 | task.options.version = true; |
jjg@46 | 122 | } |
jjg@46 | 123 | }, |
jjg@46 | 124 | |
jjg@46 | 125 | new Option(false, "-fullversion") { |
jjg@46 | 126 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 127 | task.options.fullVersion = true; |
jjg@46 | 128 | } |
jjg@46 | 129 | }, |
jjg@46 | 130 | |
jjg@46 | 131 | new Option(false, "-v", "-verbose", "-all") { |
jjg@46 | 132 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 133 | task.options.verbose = true; |
jjg@46 | 134 | task.options.showFlags = true; |
jjg@46 | 135 | task.options.showAllAttrs = true; |
jjg@46 | 136 | } |
jjg@46 | 137 | }, |
jjg@46 | 138 | |
jjg@46 | 139 | new Option(false, "-l") { |
jjg@46 | 140 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 141 | task.options.showLineAndLocalVariableTables = true; |
jjg@46 | 142 | } |
jjg@46 | 143 | }, |
jjg@46 | 144 | |
jjg@46 | 145 | new Option(false, "-public") { |
jjg@46 | 146 | void process(JavapTask task, String opt, String arg) { |
jjg@68 | 147 | task.options.accessOptions.add(opt); |
jjg@46 | 148 | task.options.showAccess = AccessFlags.ACC_PUBLIC; |
jjg@46 | 149 | } |
jjg@46 | 150 | }, |
jjg@46 | 151 | |
jjg@46 | 152 | new Option(false, "-protected") { |
jjg@46 | 153 | void process(JavapTask task, String opt, String arg) { |
jjg@68 | 154 | task.options.accessOptions.add(opt); |
jjg@46 | 155 | task.options.showAccess = AccessFlags.ACC_PROTECTED; |
jjg@46 | 156 | } |
jjg@46 | 157 | }, |
jjg@46 | 158 | |
jjg@46 | 159 | new Option(false, "-package") { |
jjg@46 | 160 | void process(JavapTask task, String opt, String arg) { |
jjg@68 | 161 | task.options.accessOptions.add(opt); |
jjg@46 | 162 | task.options.showAccess = 0; |
jjg@46 | 163 | } |
jjg@46 | 164 | }, |
jjg@46 | 165 | |
jjg@46 | 166 | new Option(false, "-p", "-private") { |
jjg@46 | 167 | void process(JavapTask task, String opt, String arg) { |
jjg@68 | 168 | if (!task.options.accessOptions.contains("-p") && |
jjg@68 | 169 | !task.options.accessOptions.contains("-private")) { |
jjg@68 | 170 | task.options.accessOptions.add(opt); |
jjg@68 | 171 | } |
jjg@46 | 172 | task.options.showAccess = AccessFlags.ACC_PRIVATE; |
jjg@46 | 173 | } |
jjg@46 | 174 | }, |
jjg@46 | 175 | |
jjg@46 | 176 | new Option(false, "-c") { |
jjg@46 | 177 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 178 | task.options.showDisassembled = true; |
jjg@46 | 179 | } |
jjg@46 | 180 | }, |
jjg@46 | 181 | |
jjg@46 | 182 | new Option(false, "-s") { |
jjg@46 | 183 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 184 | task.options.showInternalSignatures = true; |
jjg@46 | 185 | } |
jjg@46 | 186 | }, |
jjg@46 | 187 | |
jjg@46 | 188 | // new Option(false, "-all") { |
jjg@46 | 189 | // void process(JavapTask task, String opt, String arg) { |
jjg@46 | 190 | // task.options.showAllAttrs = true; |
jjg@46 | 191 | // } |
jjg@46 | 192 | // }, |
jjg@46 | 193 | |
jjg@46 | 194 | new Option(false, "-h") { |
jjg@46 | 195 | void process(JavapTask task, String opt, String arg) throws BadArgs { |
jjg@46 | 196 | throw task.new BadArgs("err.h.not.supported"); |
jjg@46 | 197 | } |
jjg@46 | 198 | }, |
jjg@46 | 199 | |
jjg@46 | 200 | new Option(false, "-verify", "-verify-verbose") { |
jjg@46 | 201 | void process(JavapTask task, String opt, String arg) throws BadArgs { |
jjg@46 | 202 | throw task.new BadArgs("err.verify.not.supported"); |
jjg@46 | 203 | } |
jjg@46 | 204 | }, |
jjg@46 | 205 | |
jjg@88 | 206 | new Option(false, "-sysinfo") { |
jjg@88 | 207 | void process(JavapTask task, String opt, String arg) { |
jjg@88 | 208 | task.options.sysInfo = true; |
jjg@88 | 209 | } |
jjg@88 | 210 | }, |
jjg@88 | 211 | |
jjg@46 | 212 | new Option(false, "-Xold") { |
jjg@46 | 213 | void process(JavapTask task, String opt, String arg) throws BadArgs { |
jjg@46 | 214 | // -Xold is only supported as first arg when invoked from |
jjg@46 | 215 | // command line; this is handled in Main,main |
jjg@46 | 216 | throw task.new BadArgs("err.Xold.not.supported.here"); |
jjg@46 | 217 | } |
jjg@46 | 218 | }, |
jjg@46 | 219 | |
jjg@46 | 220 | new Option(false, "-Xnew") { |
jjg@46 | 221 | void process(JavapTask task, String opt, String arg) throws BadArgs { |
jjg@46 | 222 | // ignore: this _is_ the new version |
jjg@46 | 223 | } |
jjg@46 | 224 | }, |
jjg@46 | 225 | |
jjg@46 | 226 | new Option(false, "-XDcompat") { |
jjg@46 | 227 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 228 | task.options.compat = true; |
jjg@46 | 229 | } |
jjg@46 | 230 | }, |
jjg@46 | 231 | |
jjg@46 | 232 | new Option(false, "-XDjsr277") { |
jjg@46 | 233 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 234 | task.options.jsr277 = true; |
jjg@46 | 235 | } |
jjg@46 | 236 | }, |
jjg@46 | 237 | |
jjg@46 | 238 | new Option(false, "-XDignore.symbol.file") { |
jjg@46 | 239 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 240 | task.options.ignoreSymbolFile = true; |
jjg@46 | 241 | } |
jjg@87 | 242 | }, |
jjg@87 | 243 | |
jjg@87 | 244 | new Option(false, "-constants") { |
jjg@87 | 245 | void process(JavapTask task, String opt, String arg) { |
jjg@87 | 246 | task.options.showConstants = true; |
jjg@87 | 247 | } |
jjg@46 | 248 | } |
jjg@46 | 249 | |
jjg@46 | 250 | }; |
jjg@46 | 251 | |
jjg@46 | 252 | JavapTask() { |
jjg@46 | 253 | context = new Context(); |
jjg@46 | 254 | options = Options.instance(context); |
jjg@46 | 255 | } |
jjg@46 | 256 | |
jjg@46 | 257 | JavapTask(Writer out, |
jjg@46 | 258 | JavaFileManager fileManager, |
jjg@46 | 259 | DiagnosticListener<? super JavaFileObject> diagnosticListener, |
jjg@46 | 260 | Iterable<String> options, |
jjg@46 | 261 | Iterable<String> classes) { |
jjg@46 | 262 | this(); |
jjg@46 | 263 | this.log = getPrintWriterForWriter(out); |
jjg@46 | 264 | this.fileManager = fileManager; |
jjg@46 | 265 | this.diagnosticListener = diagnosticListener; |
jjg@46 | 266 | |
jjg@46 | 267 | try { |
jjg@46 | 268 | handleOptions(options, false); |
jjg@46 | 269 | } catch (BadArgs e) { |
jjg@46 | 270 | throw new IllegalArgumentException(e.getMessage()); |
jjg@46 | 271 | } |
jjg@46 | 272 | |
jjg@46 | 273 | this.classes = new ArrayList<String>(); |
jjg@46 | 274 | for (String classname: classes) { |
jjg@46 | 275 | classname.getClass(); // null-check |
jjg@46 | 276 | this.classes.add(classname); |
jjg@46 | 277 | } |
jjg@46 | 278 | } |
jjg@46 | 279 | |
jjg@46 | 280 | public void setLocale(Locale locale) { |
jjg@46 | 281 | if (locale == null) |
jjg@46 | 282 | locale = Locale.getDefault(); |
jjg@46 | 283 | task_locale = locale; |
jjg@46 | 284 | } |
jjg@46 | 285 | |
jjg@46 | 286 | public void setLog(PrintWriter log) { |
jjg@46 | 287 | this.log = log; |
jjg@46 | 288 | } |
jjg@46 | 289 | |
jjg@46 | 290 | public void setLog(OutputStream s) { |
jjg@46 | 291 | setLog(getPrintWriterForStream(s)); |
jjg@46 | 292 | } |
jjg@46 | 293 | |
jjg@46 | 294 | private static PrintWriter getPrintWriterForStream(OutputStream s) { |
jjg@46 | 295 | return new PrintWriter(s, true); |
jjg@46 | 296 | } |
jjg@46 | 297 | |
jjg@46 | 298 | private static PrintWriter getPrintWriterForWriter(Writer w) { |
jjg@46 | 299 | if (w == null) |
jjg@46 | 300 | return getPrintWriterForStream(null); |
jjg@46 | 301 | else if (w instanceof PrintWriter) |
jjg@46 | 302 | return (PrintWriter) w; |
jjg@46 | 303 | else |
jjg@46 | 304 | return new PrintWriter(w, true); |
jjg@46 | 305 | } |
jjg@46 | 306 | |
jjg@46 | 307 | public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) { |
jjg@46 | 308 | diagnosticListener = dl; |
jjg@46 | 309 | } |
jjg@46 | 310 | |
jjg@46 | 311 | public void setDiagnosticListener(OutputStream s) { |
jjg@46 | 312 | setDiagnosticListener(getDiagnosticListenerForStream(s)); |
jjg@46 | 313 | } |
jjg@46 | 314 | |
jjg@46 | 315 | private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) { |
jjg@46 | 316 | return getDiagnosticListenerForWriter(getPrintWriterForStream(s)); |
jjg@46 | 317 | } |
jjg@46 | 318 | |
jjg@46 | 319 | private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) { |
jjg@46 | 320 | final PrintWriter pw = getPrintWriterForWriter(w); |
jjg@46 | 321 | return new DiagnosticListener<JavaFileObject> () { |
jjg@46 | 322 | public void report(Diagnostic<? extends JavaFileObject> diagnostic) { |
jjg@46 | 323 | if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { |
jjg@66 | 324 | pw.print(getMessage("err.prefix")); |
jjg@46 | 325 | pw.print(" "); |
jjg@46 | 326 | } |
jjg@46 | 327 | pw.println(diagnostic.getMessage(null)); |
jjg@46 | 328 | } |
jjg@46 | 329 | }; |
jjg@46 | 330 | } |
jjg@46 | 331 | |
jjg@64 | 332 | /** Result codes. |
jjg@64 | 333 | */ |
jjg@64 | 334 | static final int |
jjg@64 | 335 | EXIT_OK = 0, // Compilation completed with no errors. |
jjg@64 | 336 | EXIT_ERROR = 1, // Completed but reported errors. |
jjg@64 | 337 | EXIT_CMDERR = 2, // Bad command-line arguments |
jjg@64 | 338 | EXIT_SYSERR = 3, // System error or resource exhaustion. |
jjg@64 | 339 | EXIT_ABNORMAL = 4; // Compiler terminated abnormally |
jjg@64 | 340 | |
jjg@46 | 341 | int run(String[] args) { |
jjg@46 | 342 | try { |
jjg@46 | 343 | handleOptions(args); |
jjg@64 | 344 | |
jjg@64 | 345 | // the following gives consistent behavior with javac |
jjg@64 | 346 | if (classes == null || classes.size() == 0) { |
jjg@64 | 347 | if (options.help || options.version || options.fullVersion) |
jjg@64 | 348 | return EXIT_OK; |
jjg@64 | 349 | else |
jjg@64 | 350 | return EXIT_CMDERR; |
jjg@64 | 351 | } |
jjg@64 | 352 | |
jjg@46 | 353 | boolean ok = run(); |
jjg@64 | 354 | return ok ? EXIT_OK : EXIT_ERROR; |
jjg@46 | 355 | } catch (BadArgs e) { |
jjg@46 | 356 | diagnosticListener.report(createDiagnostic(e.key, e.args)); |
jjg@66 | 357 | if (e.showUsage) { |
jjg@66 | 358 | log.println(getMessage("main.usage.summary", progname)); |
jjg@66 | 359 | } |
jjg@64 | 360 | return EXIT_CMDERR; |
jjg@46 | 361 | } catch (InternalError e) { |
jjg@46 | 362 | Object[] e_args; |
jjg@46 | 363 | if (e.getCause() == null) |
jjg@46 | 364 | e_args = e.args; |
jjg@46 | 365 | else { |
jjg@46 | 366 | e_args = new Object[e.args.length + 1]; |
jjg@46 | 367 | e_args[0] = e.getCause(); |
jjg@46 | 368 | System.arraycopy(e.args, 0, e_args, 1, e.args.length); |
jjg@46 | 369 | } |
jjg@46 | 370 | diagnosticListener.report(createDiagnostic("err.internal.error", e_args)); |
jjg@64 | 371 | return EXIT_ABNORMAL; |
jjg@46 | 372 | } finally { |
jjg@46 | 373 | log.flush(); |
jjg@46 | 374 | } |
jjg@46 | 375 | } |
jjg@46 | 376 | |
jjg@46 | 377 | public void handleOptions(String[] args) throws BadArgs { |
jjg@46 | 378 | handleOptions(Arrays.asList(args), true); |
jjg@46 | 379 | } |
jjg@46 | 380 | |
jjg@46 | 381 | private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs { |
jjg@46 | 382 | if (log == null) { |
jjg@46 | 383 | log = getPrintWriterForStream(System.out); |
jjg@46 | 384 | if (diagnosticListener == null) |
jjg@46 | 385 | diagnosticListener = getDiagnosticListenerForStream(System.err); |
jjg@46 | 386 | } else { |
jjg@46 | 387 | if (diagnosticListener == null) |
jjg@46 | 388 | diagnosticListener = getDiagnosticListenerForWriter(log); |
jjg@46 | 389 | } |
jjg@46 | 390 | |
jjg@46 | 391 | |
jjg@46 | 392 | if (fileManager == null) |
jjg@46 | 393 | fileManager = getDefaultFileManager(diagnosticListener, log); |
jjg@46 | 394 | |
jjg@46 | 395 | Iterator<String> iter = args.iterator(); |
jjg@64 | 396 | boolean noArgs = !iter.hasNext(); |
jjg@46 | 397 | |
jjg@46 | 398 | while (iter.hasNext()) { |
jjg@46 | 399 | String arg = iter.next(); |
jjg@46 | 400 | if (arg.startsWith("-")) |
jjg@46 | 401 | handleOption(arg, iter); |
jjg@46 | 402 | else if (allowClasses) { |
jjg@46 | 403 | if (classes == null) |
jjg@46 | 404 | classes = new ArrayList<String>(); |
jjg@46 | 405 | classes.add(arg); |
jjg@46 | 406 | while (iter.hasNext()) |
jjg@46 | 407 | classes.add(iter.next()); |
jjg@46 | 408 | } else |
jjg@46 | 409 | throw new BadArgs("err.unknown.option", arg).showUsage(true); |
jjg@46 | 410 | } |
jjg@46 | 411 | |
jjg@68 | 412 | if (!options.compat && options.accessOptions.size() > 1) { |
jjg@68 | 413 | StringBuilder sb = new StringBuilder(); |
jjg@68 | 414 | for (String opt: options.accessOptions) { |
jjg@68 | 415 | if (sb.length() > 0) |
jjg@68 | 416 | sb.append(" "); |
jjg@68 | 417 | sb.append(opt); |
jjg@68 | 418 | } |
jjg@68 | 419 | throw new BadArgs("err.incompatible.options", sb); |
jjg@68 | 420 | } |
jjg@68 | 421 | |
jjg@46 | 422 | if (options.ignoreSymbolFile && fileManager instanceof JavapFileManager) |
jjg@46 | 423 | ((JavapFileManager) fileManager).setIgnoreSymbolFile(true); |
jjg@46 | 424 | |
jjg@46 | 425 | if ((classes == null || classes.size() == 0) && |
jjg@64 | 426 | !(noArgs || options.help || options.version || options.fullVersion)) { |
jjg@46 | 427 | throw new BadArgs("err.no.classes.specified"); |
jjg@46 | 428 | } |
jjg@64 | 429 | |
jjg@64 | 430 | if (noArgs || options.help) |
jjg@64 | 431 | showHelp(); |
jjg@64 | 432 | |
jjg@64 | 433 | if (options.version || options.fullVersion) |
jjg@64 | 434 | showVersion(options.fullVersion); |
jjg@46 | 435 | } |
jjg@46 | 436 | |
jjg@46 | 437 | private void handleOption(String name, Iterator<String> rest) throws BadArgs { |
jjg@46 | 438 | for (Option o: recognizedOptions) { |
jjg@46 | 439 | if (o.matches(name)) { |
jjg@46 | 440 | if (o.hasArg) { |
jjg@46 | 441 | if (rest.hasNext()) |
jjg@46 | 442 | o.process(this, name, rest.next()); |
jjg@46 | 443 | else |
jjg@46 | 444 | throw new BadArgs("err.missing.arg", name).showUsage(true); |
jjg@46 | 445 | } else |
jjg@46 | 446 | o.process(this, name, null); |
jjg@46 | 447 | |
jjg@46 | 448 | if (o.ignoreRest()) { |
jjg@46 | 449 | while (rest.hasNext()) |
jjg@46 | 450 | rest.next(); |
jjg@46 | 451 | } |
jjg@46 | 452 | return; |
jjg@46 | 453 | } |
jjg@46 | 454 | } |
jjg@46 | 455 | |
jjg@46 | 456 | if (fileManager.handleOption(name, rest)) |
jjg@46 | 457 | return; |
jjg@46 | 458 | |
jjg@46 | 459 | throw new BadArgs("err.unknown.option", name).showUsage(true); |
jjg@46 | 460 | } |
jjg@46 | 461 | |
jjg@46 | 462 | public Boolean call() { |
jjg@46 | 463 | return run(); |
jjg@46 | 464 | } |
jjg@46 | 465 | |
jjg@46 | 466 | public boolean run() { |
jjg@46 | 467 | if (classes == null || classes.size() == 0) |
jjg@64 | 468 | return false; |
jjg@46 | 469 | |
jjg@46 | 470 | context.put(PrintWriter.class, log); |
jjg@46 | 471 | ClassWriter classWriter = ClassWriter.instance(context); |
jjg@46 | 472 | |
jjg@46 | 473 | boolean ok = true; |
jjg@46 | 474 | |
jjg@46 | 475 | for (String className: classes) { |
jjg@46 | 476 | JavaFileObject fo; |
jjg@46 | 477 | try { |
jjg@46 | 478 | if (className.endsWith(".class")) { |
jjg@46 | 479 | if (fileManager instanceof StandardJavaFileManager) { |
jjg@46 | 480 | StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager; |
jjg@46 | 481 | fo = sfm.getJavaFileObjects(className).iterator().next(); |
jjg@46 | 482 | } else { |
jjg@46 | 483 | diagnosticListener.report(createDiagnostic("err.not.standard.file.manager", className)); |
jjg@46 | 484 | ok = false; |
jjg@46 | 485 | continue; |
jjg@46 | 486 | } |
jjg@46 | 487 | } else { |
jjg@46 | 488 | fo = getClassFileObject(className); |
jjg@46 | 489 | if (fo == null) { |
jjg@46 | 490 | // see if it is an inner class, by replacing dots to $, starting from the right |
jjg@46 | 491 | String cn = className; |
jjg@46 | 492 | int lastDot; |
jjg@46 | 493 | while (fo == null && (lastDot = cn.lastIndexOf(".")) != -1) { |
jjg@46 | 494 | cn = cn.substring(0, lastDot) + "$" + cn.substring(lastDot + 1); |
jjg@46 | 495 | fo = getClassFileObject(cn); |
jjg@46 | 496 | } |
jjg@46 | 497 | } |
jjg@46 | 498 | if (fo == null) { |
jjg@46 | 499 | diagnosticListener.report(createDiagnostic("err.class.not.found", className)); |
jjg@46 | 500 | ok = false; |
jjg@46 | 501 | continue; |
jjg@46 | 502 | } |
jjg@46 | 503 | } |
jjg@46 | 504 | Attribute.Factory attributeFactory = new Attribute.Factory(); |
jjg@46 | 505 | attributeFactory.setCompat(options.compat); |
jjg@46 | 506 | attributeFactory.setJSR277(options.jsr277); |
jjg@88 | 507 | |
jjg@88 | 508 | InputStream in = fo.openInputStream(); |
jjg@88 | 509 | SizeInputStream sizeIn = null; |
jjg@88 | 510 | MessageDigest md = null; |
jjg@88 | 511 | if (options.sysInfo || options.verbose) { |
jjg@88 | 512 | md = MessageDigest.getInstance("MD5"); |
jjg@88 | 513 | in = new DigestInputStream(in, md); |
jjg@88 | 514 | in = sizeIn = new SizeInputStream(in); |
jjg@88 | 515 | } |
jjg@88 | 516 | |
jjg@88 | 517 | ClassFile cf = ClassFile.read(in, attributeFactory); |
jjg@88 | 518 | |
jjg@88 | 519 | if (options.sysInfo || options.verbose) { |
jjg@88 | 520 | classWriter.setFile(fo.toUri()); |
jjg@88 | 521 | classWriter.setLastModified(fo.getLastModified()); |
jjg@88 | 522 | classWriter.setDigest("MD5", md.digest()); |
jjg@88 | 523 | classWriter.setFileSize(sizeIn.size()); |
jjg@88 | 524 | } |
jjg@88 | 525 | |
jjg@46 | 526 | classWriter.write(cf); |
jjg@88 | 527 | |
jjg@46 | 528 | } catch (ConstantPoolException e) { |
jjg@46 | 529 | diagnosticListener.report(createDiagnostic("err.bad.constant.pool", className, e.getLocalizedMessage())); |
jjg@46 | 530 | ok = false; |
jjg@46 | 531 | } catch (EOFException e) { |
jjg@46 | 532 | diagnosticListener.report(createDiagnostic("err.end.of.file", className)); |
jjg@46 | 533 | ok = false; |
jjg@46 | 534 | } catch (FileNotFoundException e) { |
jjg@46 | 535 | diagnosticListener.report(createDiagnostic("err.file.not.found", e.getLocalizedMessage())); |
jjg@46 | 536 | ok = false; |
jjg@46 | 537 | } catch (IOException e) { |
jjg@46 | 538 | //e.printStackTrace(); |
jjg@46 | 539 | Object msg = e.getLocalizedMessage(); |
jjg@46 | 540 | if (msg == null) |
jjg@46 | 541 | msg = e; |
jjg@46 | 542 | diagnosticListener.report(createDiagnostic("err.ioerror", className, msg)); |
jjg@46 | 543 | ok = false; |
jjg@46 | 544 | } catch (Throwable t) { |
jjg@46 | 545 | StringWriter sw = new StringWriter(); |
jjg@46 | 546 | PrintWriter pw = new PrintWriter(sw); |
jjg@46 | 547 | t.printStackTrace(pw); |
jjg@46 | 548 | pw.close(); |
jjg@46 | 549 | diagnosticListener.report(createDiagnostic("err.crash", t.toString(), sw.toString())); |
jjg@52 | 550 | ok = false; |
jjg@46 | 551 | } |
jjg@46 | 552 | } |
jjg@46 | 553 | |
jjg@46 | 554 | return ok; |
jjg@46 | 555 | } |
jjg@46 | 556 | |
jjg@46 | 557 | private JavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) { |
jjg@46 | 558 | return JavapFileManager.create(dl, log, options); |
jjg@46 | 559 | } |
jjg@46 | 560 | |
jjg@46 | 561 | private JavaFileObject getClassFileObject(String className) throws IOException { |
jjg@46 | 562 | JavaFileObject fo; |
jjg@46 | 563 | fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS); |
jjg@46 | 564 | if (fo == null) |
jjg@46 | 565 | fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS); |
jjg@46 | 566 | return fo; |
jjg@46 | 567 | } |
jjg@46 | 568 | |
jjg@46 | 569 | private void showHelp() { |
jjg@46 | 570 | log.println(getMessage("main.usage", progname)); |
jjg@46 | 571 | for (Option o: recognizedOptions) { |
jjg@46 | 572 | String name = o.aliases[0].substring(1); // there must always be at least one name |
jjg@46 | 573 | if (name.startsWith("X") || name.equals("fullversion") || name.equals("h") || name.equals("verify")) |
jjg@46 | 574 | continue; |
jjg@46 | 575 | log.println(getMessage("main.opt." + name)); |
jjg@46 | 576 | } |
jjg@46 | 577 | String[] fmOptions = { "-classpath", "-bootclasspath" }; |
jjg@46 | 578 | for (String o: fmOptions) { |
jjg@46 | 579 | if (fileManager.isSupportedOption(o) == -1) |
jjg@46 | 580 | continue; |
jjg@46 | 581 | String name = o.substring(1); |
jjg@46 | 582 | log.println(getMessage("main.opt." + name)); |
jjg@46 | 583 | } |
jjg@46 | 584 | |
jjg@46 | 585 | } |
jjg@46 | 586 | |
jjg@46 | 587 | private void showVersion(boolean full) { |
jjg@46 | 588 | log.println(version(full ? "full" : "release")); |
jjg@46 | 589 | } |
jjg@46 | 590 | |
jjg@46 | 591 | private static final String versionRBName = "com.sun.tools.javap.resources.version"; |
jjg@46 | 592 | private static ResourceBundle versionRB; |
jjg@46 | 593 | |
jjg@46 | 594 | private String version(String key) { |
jjg@46 | 595 | // key=version: mm.nn.oo[-milestone] |
jjg@46 | 596 | // key=full: mm.mm.oo[-milestone]-build |
jjg@46 | 597 | if (versionRB == null) { |
jjg@46 | 598 | try { |
jjg@46 | 599 | versionRB = ResourceBundle.getBundle(versionRBName); |
jjg@46 | 600 | } catch (MissingResourceException e) { |
jjg@46 | 601 | return getMessage("version.resource.missing", System.getProperty("java.version")); |
jjg@46 | 602 | } |
jjg@46 | 603 | } |
jjg@46 | 604 | try { |
jjg@46 | 605 | return versionRB.getString(key); |
jjg@46 | 606 | } |
jjg@46 | 607 | catch (MissingResourceException e) { |
jjg@46 | 608 | return getMessage("version.unknown", System.getProperty("java.version")); |
jjg@46 | 609 | } |
jjg@46 | 610 | } |
jjg@46 | 611 | |
jjg@46 | 612 | private Diagnostic<JavaFileObject> createDiagnostic(final String key, final Object... args) { |
jjg@46 | 613 | return new Diagnostic<JavaFileObject>() { |
jjg@46 | 614 | public Kind getKind() { |
jjg@46 | 615 | return Diagnostic.Kind.ERROR; |
jjg@46 | 616 | } |
jjg@46 | 617 | |
jjg@46 | 618 | public JavaFileObject getSource() { |
jjg@46 | 619 | return null; |
jjg@46 | 620 | } |
jjg@46 | 621 | |
jjg@46 | 622 | public long getPosition() { |
jjg@46 | 623 | return Diagnostic.NOPOS; |
jjg@46 | 624 | } |
jjg@46 | 625 | |
jjg@46 | 626 | public long getStartPosition() { |
jjg@46 | 627 | return Diagnostic.NOPOS; |
jjg@46 | 628 | } |
jjg@46 | 629 | |
jjg@46 | 630 | public long getEndPosition() { |
jjg@46 | 631 | return Diagnostic.NOPOS; |
jjg@46 | 632 | } |
jjg@46 | 633 | |
jjg@46 | 634 | public long getLineNumber() { |
jjg@46 | 635 | return Diagnostic.NOPOS; |
jjg@46 | 636 | } |
jjg@46 | 637 | |
jjg@46 | 638 | public long getColumnNumber() { |
jjg@46 | 639 | return Diagnostic.NOPOS; |
jjg@46 | 640 | } |
jjg@46 | 641 | |
jjg@46 | 642 | public String getCode() { |
jjg@46 | 643 | return key; |
jjg@46 | 644 | } |
jjg@46 | 645 | |
jjg@46 | 646 | public String getMessage(Locale locale) { |
jjg@46 | 647 | return JavapTask.this.getMessage(locale, key, args); |
jjg@46 | 648 | } |
jjg@46 | 649 | |
jjg@46 | 650 | }; |
jjg@46 | 651 | |
jjg@46 | 652 | } |
jjg@46 | 653 | |
jjg@46 | 654 | private String getMessage(String key, Object... args) { |
jjg@46 | 655 | return getMessage(task_locale, key, args); |
jjg@46 | 656 | } |
jjg@46 | 657 | |
jjg@46 | 658 | private String getMessage(Locale locale, String key, Object... args) { |
jjg@46 | 659 | if (bundles == null) { |
jjg@46 | 660 | // could make this a HashMap<Locale,SoftReference<ResourceBundle>> |
jjg@46 | 661 | // and for efficiency, keep a hard reference to the bundle for the task |
jjg@46 | 662 | // locale |
jjg@46 | 663 | bundles = new HashMap<Locale, ResourceBundle>(); |
jjg@46 | 664 | } |
jjg@46 | 665 | |
jjg@46 | 666 | if (locale == null) |
jjg@46 | 667 | locale = Locale.getDefault(); |
jjg@46 | 668 | |
jjg@46 | 669 | ResourceBundle b = bundles.get(locale); |
jjg@46 | 670 | if (b == null) { |
jjg@46 | 671 | try { |
jjg@46 | 672 | b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap", locale); |
jjg@46 | 673 | bundles.put(locale, b); |
jjg@46 | 674 | } catch (MissingResourceException e) { |
jjg@46 | 675 | throw new InternalError("Cannot find javap resource bundle for locale " + locale); |
jjg@46 | 676 | } |
jjg@46 | 677 | } |
jjg@46 | 678 | |
jjg@46 | 679 | try { |
jjg@46 | 680 | return MessageFormat.format(b.getString(key), args); |
jjg@46 | 681 | } catch (MissingResourceException e) { |
jjg@46 | 682 | throw new InternalError(e, key); |
jjg@46 | 683 | } |
jjg@46 | 684 | } |
jjg@46 | 685 | |
jjg@46 | 686 | Context context; |
jjg@46 | 687 | JavaFileManager fileManager; |
jjg@46 | 688 | PrintWriter log; |
jjg@46 | 689 | DiagnosticListener<? super JavaFileObject> diagnosticListener; |
jjg@46 | 690 | List<String> classes; |
jjg@46 | 691 | Options options; |
jjg@46 | 692 | //ResourceBundle bundle; |
jjg@46 | 693 | Locale task_locale; |
jjg@46 | 694 | Map<Locale, ResourceBundle> bundles; |
jjg@46 | 695 | |
jjg@46 | 696 | private static final String progname = "javap"; |
jjg@88 | 697 | |
jjg@88 | 698 | private static class SizeInputStream extends FilterInputStream { |
jjg@88 | 699 | SizeInputStream(InputStream in) { |
jjg@88 | 700 | super(in); |
jjg@88 | 701 | } |
jjg@88 | 702 | |
jjg@88 | 703 | int size() { |
jjg@88 | 704 | return size; |
jjg@88 | 705 | } |
jjg@88 | 706 | |
jjg@88 | 707 | @Override |
jjg@88 | 708 | public int read(byte[] buf, int offset, int length) throws IOException { |
jjg@88 | 709 | int n = super.read(buf, offset, length); |
jjg@88 | 710 | if (n > 0) |
jjg@88 | 711 | size += n; |
jjg@88 | 712 | return n; |
jjg@88 | 713 | } |
jjg@88 | 714 | |
jjg@88 | 715 | @Override |
jjg@88 | 716 | public int read() throws IOException { |
jjg@88 | 717 | int b = super.read(); |
jjg@88 | 718 | size += 1; |
jjg@88 | 719 | return b; |
jjg@88 | 720 | } |
jjg@88 | 721 | |
jjg@88 | 722 | private int size; |
jjg@88 | 723 | } |
jjg@46 | 724 | } |