Wed, 17 Nov 2010 15:07:43 -0800
7000973: isBogus needs to be called on the to-be-returned entry, not on the current entry
Reviewed-by: jjg
Contributed-by: jan.lahoda@oracle.com
jjg@46 | 1 | /* |
ohair@554 | 2 | * Copyright (c) 2007, 2009, Oracle and/or its affiliates. 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 |
ohair@554 | 7 | * published by the Free Software Foundation. Oracle designates this |
jjg@46 | 8 | * particular file as subject to the "Classpath" exception as provided |
ohair@554 | 9 | * by Oracle 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@90 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
jjg@46 | 20 | * |
ohair@554 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
ohair@554 | 22 | * or visit www.oracle.com if you need additional information or have any |
ohair@554 | 23 | * 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@350 | 35 | import java.io.Reader; |
jjg@46 | 36 | import java.io.StringWriter; |
jjg@46 | 37 | import java.io.Writer; |
jjg@350 | 38 | import java.net.URI; |
jjg@88 | 39 | import java.security.DigestInputStream; |
jjg@88 | 40 | import java.security.MessageDigest; |
jjg@300 | 41 | import java.security.NoSuchAlgorithmException; |
jjg@46 | 42 | import java.text.MessageFormat; |
jjg@46 | 43 | import java.util.ArrayList; |
jjg@46 | 44 | import java.util.Arrays; |
jjg@283 | 45 | import java.util.EnumSet; |
jjg@46 | 46 | import java.util.HashMap; |
jjg@46 | 47 | import java.util.Iterator; |
jjg@46 | 48 | import java.util.List; |
jjg@46 | 49 | import java.util.Locale; |
jjg@46 | 50 | import java.util.Map; |
jjg@46 | 51 | import java.util.MissingResourceException; |
jjg@46 | 52 | import java.util.ResourceBundle; |
jjg@46 | 53 | |
jjg@350 | 54 | import javax.lang.model.element.Modifier; |
jjg@350 | 55 | import javax.lang.model.element.NestingKind; |
jjg@46 | 56 | import javax.tools.Diagnostic; |
jjg@46 | 57 | import javax.tools.DiagnosticListener; |
jjg@46 | 58 | import javax.tools.JavaFileManager; |
jjg@46 | 59 | import javax.tools.JavaFileObject; |
jjg@46 | 60 | import javax.tools.StandardJavaFileManager; |
jjg@46 | 61 | import javax.tools.StandardLocation; |
jjg@46 | 62 | |
jjg@46 | 63 | import com.sun.tools.classfile.*; |
jjg@350 | 64 | import java.net.URISyntaxException; |
jjg@350 | 65 | import java.net.URL; |
jjg@350 | 66 | import java.net.URLConnection; |
jjg@46 | 67 | |
jjg@46 | 68 | /** |
jjg@46 | 69 | * "Main" class for javap, normally accessed from the command line |
jjg@46 | 70 | * via Main, or from JSR199 via DisassemblerTool. |
jjg@46 | 71 | * |
jjg@581 | 72 | * <p><b>This is NOT part of any supported API. |
jjg@581 | 73 | * If you write code that depends on this, you do so at your own risk. |
jjg@46 | 74 | * This code and its internal interfaces are subject to change or |
jjg@46 | 75 | * deletion without notice.</b> |
jjg@46 | 76 | */ |
jjg@283 | 77 | public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages { |
jjg@46 | 78 | public class BadArgs extends Exception { |
jjg@46 | 79 | static final long serialVersionUID = 8765093759964640721L; |
jjg@46 | 80 | BadArgs(String key, Object... args) { |
jjg@46 | 81 | super(JavapTask.this.getMessage(key, args)); |
jjg@46 | 82 | this.key = key; |
jjg@46 | 83 | this.args = args; |
jjg@46 | 84 | } |
jjg@46 | 85 | |
jjg@46 | 86 | BadArgs showUsage(boolean b) { |
jjg@46 | 87 | showUsage = b; |
jjg@46 | 88 | return this; |
jjg@46 | 89 | } |
jjg@46 | 90 | |
jjg@46 | 91 | final String key; |
jjg@46 | 92 | final Object[] args; |
jjg@46 | 93 | boolean showUsage; |
jjg@46 | 94 | } |
jjg@46 | 95 | |
jjg@46 | 96 | static abstract class Option { |
jjg@46 | 97 | Option(boolean hasArg, String... aliases) { |
jjg@46 | 98 | this.hasArg = hasArg; |
jjg@46 | 99 | this.aliases = aliases; |
jjg@46 | 100 | } |
jjg@46 | 101 | |
jjg@46 | 102 | boolean matches(String opt) { |
jjg@46 | 103 | for (String a: aliases) { |
jjg@46 | 104 | if (a.equals(opt)) |
jjg@46 | 105 | return true; |
jjg@46 | 106 | } |
jjg@46 | 107 | return false; |
jjg@46 | 108 | } |
jjg@46 | 109 | |
jjg@46 | 110 | boolean ignoreRest() { |
jjg@46 | 111 | return false; |
jjg@46 | 112 | } |
jjg@46 | 113 | |
jjg@46 | 114 | abstract void process(JavapTask task, String opt, String arg) throws BadArgs; |
jjg@46 | 115 | |
jjg@46 | 116 | final boolean hasArg; |
jjg@46 | 117 | final String[] aliases; |
jjg@46 | 118 | } |
jjg@46 | 119 | |
jjg@46 | 120 | static Option[] recognizedOptions = { |
jjg@46 | 121 | |
jjg@46 | 122 | new Option(false, "-help", "--help", "-?") { |
jjg@46 | 123 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 124 | task.options.help = true; |
jjg@46 | 125 | } |
jjg@46 | 126 | }, |
jjg@46 | 127 | |
jjg@46 | 128 | new Option(false, "-version") { |
jjg@46 | 129 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 130 | task.options.version = true; |
jjg@46 | 131 | } |
jjg@46 | 132 | }, |
jjg@46 | 133 | |
jjg@46 | 134 | new Option(false, "-fullversion") { |
jjg@46 | 135 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 136 | task.options.fullVersion = true; |
jjg@46 | 137 | } |
jjg@46 | 138 | }, |
jjg@46 | 139 | |
jjg@46 | 140 | new Option(false, "-v", "-verbose", "-all") { |
jjg@46 | 141 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 142 | task.options.verbose = true; |
jjg@46 | 143 | task.options.showFlags = true; |
jjg@46 | 144 | task.options.showAllAttrs = true; |
jjg@46 | 145 | } |
jjg@46 | 146 | }, |
jjg@46 | 147 | |
jjg@46 | 148 | new Option(false, "-l") { |
jjg@46 | 149 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 150 | task.options.showLineAndLocalVariableTables = true; |
jjg@46 | 151 | } |
jjg@46 | 152 | }, |
jjg@46 | 153 | |
jjg@46 | 154 | new Option(false, "-public") { |
jjg@46 | 155 | void process(JavapTask task, String opt, String arg) { |
jjg@68 | 156 | task.options.accessOptions.add(opt); |
jjg@46 | 157 | task.options.showAccess = AccessFlags.ACC_PUBLIC; |
jjg@46 | 158 | } |
jjg@46 | 159 | }, |
jjg@46 | 160 | |
jjg@46 | 161 | new Option(false, "-protected") { |
jjg@46 | 162 | void process(JavapTask task, String opt, String arg) { |
jjg@68 | 163 | task.options.accessOptions.add(opt); |
jjg@46 | 164 | task.options.showAccess = AccessFlags.ACC_PROTECTED; |
jjg@46 | 165 | } |
jjg@46 | 166 | }, |
jjg@46 | 167 | |
jjg@46 | 168 | new Option(false, "-package") { |
jjg@46 | 169 | void process(JavapTask task, String opt, String arg) { |
jjg@68 | 170 | task.options.accessOptions.add(opt); |
jjg@46 | 171 | task.options.showAccess = 0; |
jjg@46 | 172 | } |
jjg@46 | 173 | }, |
jjg@46 | 174 | |
jjg@46 | 175 | new Option(false, "-p", "-private") { |
jjg@46 | 176 | void process(JavapTask task, String opt, String arg) { |
jjg@68 | 177 | if (!task.options.accessOptions.contains("-p") && |
jjg@68 | 178 | !task.options.accessOptions.contains("-private")) { |
jjg@68 | 179 | task.options.accessOptions.add(opt); |
jjg@68 | 180 | } |
jjg@46 | 181 | task.options.showAccess = AccessFlags.ACC_PRIVATE; |
jjg@46 | 182 | } |
jjg@46 | 183 | }, |
jjg@46 | 184 | |
jjg@46 | 185 | new Option(false, "-c") { |
jjg@46 | 186 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 187 | task.options.showDisassembled = true; |
jjg@46 | 188 | } |
jjg@46 | 189 | }, |
jjg@46 | 190 | |
jjg@46 | 191 | new Option(false, "-s") { |
jjg@46 | 192 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 193 | task.options.showInternalSignatures = true; |
jjg@46 | 194 | } |
jjg@46 | 195 | }, |
jjg@46 | 196 | |
jjg@46 | 197 | // new Option(false, "-all") { |
jjg@46 | 198 | // void process(JavapTask task, String opt, String arg) { |
jjg@46 | 199 | // task.options.showAllAttrs = true; |
jjg@46 | 200 | // } |
jjg@46 | 201 | // }, |
jjg@46 | 202 | |
jjg@46 | 203 | new Option(false, "-h") { |
jjg@46 | 204 | void process(JavapTask task, String opt, String arg) throws BadArgs { |
jjg@46 | 205 | throw task.new BadArgs("err.h.not.supported"); |
jjg@46 | 206 | } |
jjg@46 | 207 | }, |
jjg@46 | 208 | |
jjg@46 | 209 | new Option(false, "-verify", "-verify-verbose") { |
jjg@46 | 210 | void process(JavapTask task, String opt, String arg) throws BadArgs { |
jjg@46 | 211 | throw task.new BadArgs("err.verify.not.supported"); |
jjg@46 | 212 | } |
jjg@46 | 213 | }, |
jjg@46 | 214 | |
jjg@88 | 215 | new Option(false, "-sysinfo") { |
jjg@88 | 216 | void process(JavapTask task, String opt, String arg) { |
jjg@88 | 217 | task.options.sysInfo = true; |
jjg@88 | 218 | } |
jjg@88 | 219 | }, |
jjg@88 | 220 | |
jjg@46 | 221 | new Option(false, "-Xold") { |
jjg@46 | 222 | void process(JavapTask task, String opt, String arg) throws BadArgs { |
jjg@291 | 223 | task.log.println(task.getMessage("warn.Xold.not.supported")); |
jjg@46 | 224 | } |
jjg@46 | 225 | }, |
jjg@46 | 226 | |
jjg@46 | 227 | new Option(false, "-Xnew") { |
jjg@46 | 228 | void process(JavapTask task, String opt, String arg) throws BadArgs { |
jjg@46 | 229 | // ignore: this _is_ the new version |
jjg@46 | 230 | } |
jjg@46 | 231 | }, |
jjg@46 | 232 | |
jjg@46 | 233 | new Option(false, "-XDcompat") { |
jjg@46 | 234 | void process(JavapTask task, String opt, String arg) { |
jjg@46 | 235 | task.options.compat = true; |
jjg@46 | 236 | } |
jjg@46 | 237 | }, |
jjg@46 | 238 | |
jjg@283 | 239 | new Option(false, "-XDdetails") { |
jjg@283 | 240 | void process(JavapTask task, String opt, String arg) { |
jjg@283 | 241 | task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class); |
jjg@283 | 242 | } |
jjg@283 | 243 | |
jjg@283 | 244 | }, |
jjg@283 | 245 | |
jjg@283 | 246 | new Option(false, "-XDdetails:") { |
jjg@283 | 247 | @Override |
jjg@283 | 248 | boolean matches(String opt) { |
jjg@283 | 249 | int sep = opt.indexOf(":"); |
jjg@283 | 250 | return sep != -1 && super.matches(opt.substring(0, sep + 1)); |
jjg@283 | 251 | } |
jjg@283 | 252 | |
jjg@283 | 253 | void process(JavapTask task, String opt, String arg) throws BadArgs { |
jjg@283 | 254 | int sep = opt.indexOf(":"); |
jjg@283 | 255 | for (String v: opt.substring(sep + 1).split("[,: ]+")) { |
jjg@283 | 256 | if (!handleArg(task, v)) |
jjg@283 | 257 | throw task.new BadArgs("err.invalid.arg.for.option", v); |
jjg@283 | 258 | } |
jjg@283 | 259 | } |
jjg@283 | 260 | |
jjg@283 | 261 | boolean handleArg(JavapTask task, String arg) { |
jjg@283 | 262 | if (arg.length() == 0) |
jjg@283 | 263 | return true; |
jjg@283 | 264 | |
jjg@283 | 265 | if (arg.equals("all")) { |
jjg@283 | 266 | task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class); |
jjg@283 | 267 | return true; |
jjg@283 | 268 | } |
jjg@283 | 269 | |
jjg@283 | 270 | boolean on = true; |
jjg@283 | 271 | if (arg.startsWith("-")) { |
jjg@283 | 272 | on = false; |
jjg@283 | 273 | arg = arg.substring(1); |
jjg@283 | 274 | } |
jjg@283 | 275 | |
jjg@283 | 276 | for (InstructionDetailWriter.Kind k: InstructionDetailWriter.Kind.values()) { |
jjg@283 | 277 | if (arg.equalsIgnoreCase(k.option)) { |
jjg@283 | 278 | if (on) |
jjg@283 | 279 | task.options.details.add(k); |
jjg@283 | 280 | else |
jjg@283 | 281 | task.options.details.remove(k); |
jjg@283 | 282 | return true; |
jjg@283 | 283 | } |
jjg@283 | 284 | } |
jjg@283 | 285 | return false; |
jjg@283 | 286 | } |
jjg@283 | 287 | }, |
jjg@283 | 288 | |
jjg@87 | 289 | new Option(false, "-constants") { |
jjg@87 | 290 | void process(JavapTask task, String opt, String arg) { |
jjg@87 | 291 | task.options.showConstants = true; |
jjg@87 | 292 | } |
jjg@346 | 293 | }, |
jjg@346 | 294 | |
jjg@346 | 295 | new Option(false, "-XDinner") { |
jjg@346 | 296 | void process(JavapTask task, String opt, String arg) { |
jjg@346 | 297 | task.options.showInnerClasses = true; |
jjg@346 | 298 | } |
jjg@348 | 299 | }, |
jjg@348 | 300 | |
jjg@348 | 301 | new Option(false, "-XDindent:") { |
jjg@348 | 302 | @Override |
jjg@348 | 303 | boolean matches(String opt) { |
jjg@348 | 304 | int sep = opt.indexOf(":"); |
jjg@348 | 305 | return sep != -1 && super.matches(opt.substring(0, sep + 1)); |
jjg@348 | 306 | } |
jjg@348 | 307 | |
jjg@348 | 308 | void process(JavapTask task, String opt, String arg) throws BadArgs { |
jjg@348 | 309 | int sep = opt.indexOf(":"); |
jjg@348 | 310 | try { |
jjg@348 | 311 | task.options.indentWidth = Integer.valueOf(opt.substring(sep + 1)); |
jjg@348 | 312 | } catch (NumberFormatException e) { |
jjg@348 | 313 | } |
jjg@348 | 314 | } |
jjg@348 | 315 | }, |
jjg@348 | 316 | |
jjg@348 | 317 | new Option(false, "-XDtab:") { |
jjg@348 | 318 | @Override |
jjg@348 | 319 | boolean matches(String opt) { |
jjg@348 | 320 | int sep = opt.indexOf(":"); |
jjg@348 | 321 | return sep != -1 && super.matches(opt.substring(0, sep + 1)); |
jjg@348 | 322 | } |
jjg@348 | 323 | |
jjg@348 | 324 | void process(JavapTask task, String opt, String arg) throws BadArgs { |
jjg@348 | 325 | int sep = opt.indexOf(":"); |
jjg@348 | 326 | try { |
jjg@348 | 327 | task.options.tabColumn = Integer.valueOf(opt.substring(sep + 1)); |
jjg@348 | 328 | } catch (NumberFormatException e) { |
jjg@348 | 329 | } |
jjg@348 | 330 | } |
jjg@46 | 331 | } |
jjg@46 | 332 | |
jjg@46 | 333 | }; |
jjg@46 | 334 | |
jjg@300 | 335 | public JavapTask() { |
jjg@46 | 336 | context = new Context(); |
jjg@283 | 337 | context.put(Messages.class, this); |
jjg@46 | 338 | options = Options.instance(context); |
jjg@300 | 339 | attributeFactory = new Attribute.Factory(); |
jjg@46 | 340 | } |
jjg@46 | 341 | |
jjg@300 | 342 | public JavapTask(Writer out, |
jjg@300 | 343 | JavaFileManager fileManager, |
jjg@300 | 344 | DiagnosticListener<? super JavaFileObject> diagnosticListener) { |
jjg@300 | 345 | this(); |
jjg@300 | 346 | this.log = getPrintWriterForWriter(out); |
jjg@300 | 347 | this.fileManager = fileManager; |
jjg@300 | 348 | this.diagnosticListener = diagnosticListener; |
jjg@300 | 349 | } |
jjg@300 | 350 | |
jjg@300 | 351 | public JavapTask(Writer out, |
jjg@46 | 352 | JavaFileManager fileManager, |
jjg@46 | 353 | DiagnosticListener<? super JavaFileObject> diagnosticListener, |
jjg@46 | 354 | Iterable<String> options, |
jjg@46 | 355 | Iterable<String> classes) { |
jjg@300 | 356 | this(out, fileManager, diagnosticListener); |
jjg@46 | 357 | |
jjg@340 | 358 | this.classes = new ArrayList<String>(); |
jjg@340 | 359 | for (String classname: classes) { |
jjg@340 | 360 | classname.getClass(); // null-check |
jjg@340 | 361 | this.classes.add(classname); |
jjg@340 | 362 | } |
jjg@340 | 363 | |
jjg@46 | 364 | try { |
jjg@46 | 365 | handleOptions(options, false); |
jjg@46 | 366 | } catch (BadArgs e) { |
jjg@46 | 367 | throw new IllegalArgumentException(e.getMessage()); |
jjg@46 | 368 | } |
jjg@46 | 369 | } |
jjg@46 | 370 | |
jjg@46 | 371 | public void setLocale(Locale locale) { |
jjg@46 | 372 | if (locale == null) |
jjg@46 | 373 | locale = Locale.getDefault(); |
jjg@46 | 374 | task_locale = locale; |
jjg@46 | 375 | } |
jjg@46 | 376 | |
jjg@46 | 377 | public void setLog(PrintWriter log) { |
jjg@46 | 378 | this.log = log; |
jjg@46 | 379 | } |
jjg@46 | 380 | |
jjg@46 | 381 | public void setLog(OutputStream s) { |
jjg@46 | 382 | setLog(getPrintWriterForStream(s)); |
jjg@46 | 383 | } |
jjg@46 | 384 | |
jjg@46 | 385 | private static PrintWriter getPrintWriterForStream(OutputStream s) { |
jjg@46 | 386 | return new PrintWriter(s, true); |
jjg@46 | 387 | } |
jjg@46 | 388 | |
jjg@46 | 389 | private static PrintWriter getPrintWriterForWriter(Writer w) { |
jjg@46 | 390 | if (w == null) |
jjg@46 | 391 | return getPrintWriterForStream(null); |
jjg@46 | 392 | else if (w instanceof PrintWriter) |
jjg@46 | 393 | return (PrintWriter) w; |
jjg@46 | 394 | else |
jjg@46 | 395 | return new PrintWriter(w, true); |
jjg@46 | 396 | } |
jjg@46 | 397 | |
jjg@46 | 398 | public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) { |
jjg@46 | 399 | diagnosticListener = dl; |
jjg@46 | 400 | } |
jjg@46 | 401 | |
jjg@46 | 402 | public void setDiagnosticListener(OutputStream s) { |
jjg@46 | 403 | setDiagnosticListener(getDiagnosticListenerForStream(s)); |
jjg@46 | 404 | } |
jjg@46 | 405 | |
jjg@46 | 406 | private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) { |
jjg@46 | 407 | return getDiagnosticListenerForWriter(getPrintWriterForStream(s)); |
jjg@46 | 408 | } |
jjg@46 | 409 | |
jjg@46 | 410 | private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) { |
jjg@46 | 411 | final PrintWriter pw = getPrintWriterForWriter(w); |
jjg@46 | 412 | return new DiagnosticListener<JavaFileObject> () { |
jjg@46 | 413 | public void report(Diagnostic<? extends JavaFileObject> diagnostic) { |
jjg@340 | 414 | switch (diagnostic.getKind()) { |
jjg@340 | 415 | case ERROR: |
jjg@66 | 416 | pw.print(getMessage("err.prefix")); |
jjg@340 | 417 | break; |
jjg@340 | 418 | case WARNING: |
jjg@340 | 419 | pw.print(getMessage("warn.prefix")); |
jjg@340 | 420 | break; |
jjg@340 | 421 | case NOTE: |
jjg@340 | 422 | pw.print(getMessage("note.prefix")); |
jjg@340 | 423 | break; |
jjg@46 | 424 | } |
jjg@340 | 425 | pw.print(" "); |
jjg@46 | 426 | pw.println(diagnostic.getMessage(null)); |
jjg@46 | 427 | } |
jjg@46 | 428 | }; |
jjg@46 | 429 | } |
jjg@46 | 430 | |
jjg@64 | 431 | /** Result codes. |
jjg@64 | 432 | */ |
jjg@64 | 433 | static final int |
jjg@64 | 434 | EXIT_OK = 0, // Compilation completed with no errors. |
jjg@64 | 435 | EXIT_ERROR = 1, // Completed but reported errors. |
jjg@64 | 436 | EXIT_CMDERR = 2, // Bad command-line arguments |
jjg@64 | 437 | EXIT_SYSERR = 3, // System error or resource exhaustion. |
jjg@64 | 438 | EXIT_ABNORMAL = 4; // Compiler terminated abnormally |
jjg@64 | 439 | |
jjg@46 | 440 | int run(String[] args) { |
jjg@46 | 441 | try { |
jjg@46 | 442 | handleOptions(args); |
jjg@64 | 443 | |
jjg@64 | 444 | // the following gives consistent behavior with javac |
jjg@64 | 445 | if (classes == null || classes.size() == 0) { |
jjg@64 | 446 | if (options.help || options.version || options.fullVersion) |
jjg@64 | 447 | return EXIT_OK; |
jjg@64 | 448 | else |
jjg@64 | 449 | return EXIT_CMDERR; |
jjg@64 | 450 | } |
jjg@64 | 451 | |
jjg@402 | 452 | try { |
jjg@402 | 453 | boolean ok = run(); |
jjg@402 | 454 | return ok ? EXIT_OK : EXIT_ERROR; |
jjg@402 | 455 | } finally { |
jjg@402 | 456 | if (defaultFileManager != null) { |
jjg@402 | 457 | try { |
jjg@402 | 458 | defaultFileManager.close(); |
jjg@402 | 459 | defaultFileManager = null; |
jjg@402 | 460 | } catch (IOException e) { |
jjg@402 | 461 | throw new InternalError(e); |
jjg@402 | 462 | } |
jjg@402 | 463 | } |
jjg@402 | 464 | } |
jjg@46 | 465 | } catch (BadArgs e) { |
jjg@340 | 466 | reportError(e.key, e.args); |
jjg@66 | 467 | if (e.showUsage) { |
jjg@66 | 468 | log.println(getMessage("main.usage.summary", progname)); |
jjg@66 | 469 | } |
jjg@64 | 470 | return EXIT_CMDERR; |
jjg@46 | 471 | } catch (InternalError e) { |
jjg@46 | 472 | Object[] e_args; |
jjg@46 | 473 | if (e.getCause() == null) |
jjg@46 | 474 | e_args = e.args; |
jjg@46 | 475 | else { |
jjg@46 | 476 | e_args = new Object[e.args.length + 1]; |
jjg@46 | 477 | e_args[0] = e.getCause(); |
jjg@46 | 478 | System.arraycopy(e.args, 0, e_args, 1, e.args.length); |
jjg@46 | 479 | } |
jjg@340 | 480 | reportError("err.internal.error", e_args); |
jjg@64 | 481 | return EXIT_ABNORMAL; |
jjg@46 | 482 | } finally { |
jjg@46 | 483 | log.flush(); |
jjg@46 | 484 | } |
jjg@46 | 485 | } |
jjg@46 | 486 | |
jjg@46 | 487 | public void handleOptions(String[] args) throws BadArgs { |
jjg@46 | 488 | handleOptions(Arrays.asList(args), true); |
jjg@46 | 489 | } |
jjg@46 | 490 | |
jjg@46 | 491 | private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs { |
jjg@46 | 492 | if (log == null) { |
jjg@46 | 493 | log = getPrintWriterForStream(System.out); |
jjg@46 | 494 | if (diagnosticListener == null) |
jjg@46 | 495 | diagnosticListener = getDiagnosticListenerForStream(System.err); |
jjg@46 | 496 | } else { |
jjg@46 | 497 | if (diagnosticListener == null) |
jjg@46 | 498 | diagnosticListener = getDiagnosticListenerForWriter(log); |
jjg@46 | 499 | } |
jjg@46 | 500 | |
jjg@46 | 501 | |
jjg@46 | 502 | if (fileManager == null) |
jjg@46 | 503 | fileManager = getDefaultFileManager(diagnosticListener, log); |
jjg@46 | 504 | |
jjg@46 | 505 | Iterator<String> iter = args.iterator(); |
jjg@64 | 506 | boolean noArgs = !iter.hasNext(); |
jjg@46 | 507 | |
jjg@46 | 508 | while (iter.hasNext()) { |
jjg@46 | 509 | String arg = iter.next(); |
jjg@46 | 510 | if (arg.startsWith("-")) |
jjg@46 | 511 | handleOption(arg, iter); |
jjg@46 | 512 | else if (allowClasses) { |
jjg@46 | 513 | if (classes == null) |
jjg@46 | 514 | classes = new ArrayList<String>(); |
jjg@46 | 515 | classes.add(arg); |
jjg@46 | 516 | while (iter.hasNext()) |
jjg@46 | 517 | classes.add(iter.next()); |
jjg@46 | 518 | } else |
jjg@46 | 519 | throw new BadArgs("err.unknown.option", arg).showUsage(true); |
jjg@46 | 520 | } |
jjg@46 | 521 | |
jjg@68 | 522 | if (!options.compat && options.accessOptions.size() > 1) { |
jjg@68 | 523 | StringBuilder sb = new StringBuilder(); |
jjg@68 | 524 | for (String opt: options.accessOptions) { |
jjg@68 | 525 | if (sb.length() > 0) |
jjg@68 | 526 | sb.append(" "); |
jjg@68 | 527 | sb.append(opt); |
jjg@68 | 528 | } |
jjg@68 | 529 | throw new BadArgs("err.incompatible.options", sb); |
jjg@68 | 530 | } |
jjg@68 | 531 | |
jjg@46 | 532 | if ((classes == null || classes.size() == 0) && |
jjg@64 | 533 | !(noArgs || options.help || options.version || options.fullVersion)) { |
jjg@46 | 534 | throw new BadArgs("err.no.classes.specified"); |
jjg@46 | 535 | } |
jjg@64 | 536 | |
jjg@64 | 537 | if (noArgs || options.help) |
jjg@64 | 538 | showHelp(); |
jjg@64 | 539 | |
jjg@64 | 540 | if (options.version || options.fullVersion) |
jjg@64 | 541 | showVersion(options.fullVersion); |
jjg@46 | 542 | } |
jjg@46 | 543 | |
jjg@46 | 544 | private void handleOption(String name, Iterator<String> rest) throws BadArgs { |
jjg@46 | 545 | for (Option o: recognizedOptions) { |
jjg@46 | 546 | if (o.matches(name)) { |
jjg@46 | 547 | if (o.hasArg) { |
jjg@46 | 548 | if (rest.hasNext()) |
jjg@46 | 549 | o.process(this, name, rest.next()); |
jjg@46 | 550 | else |
jjg@46 | 551 | throw new BadArgs("err.missing.arg", name).showUsage(true); |
jjg@46 | 552 | } else |
jjg@46 | 553 | o.process(this, name, null); |
jjg@46 | 554 | |
jjg@46 | 555 | if (o.ignoreRest()) { |
jjg@46 | 556 | while (rest.hasNext()) |
jjg@46 | 557 | rest.next(); |
jjg@46 | 558 | } |
jjg@46 | 559 | return; |
jjg@46 | 560 | } |
jjg@46 | 561 | } |
jjg@46 | 562 | |
jjg@46 | 563 | if (fileManager.handleOption(name, rest)) |
jjg@46 | 564 | return; |
jjg@46 | 565 | |
jjg@46 | 566 | throw new BadArgs("err.unknown.option", name).showUsage(true); |
jjg@46 | 567 | } |
jjg@46 | 568 | |
jjg@46 | 569 | public Boolean call() { |
jjg@46 | 570 | return run(); |
jjg@46 | 571 | } |
jjg@46 | 572 | |
jjg@46 | 573 | public boolean run() { |
jjg@46 | 574 | if (classes == null || classes.size() == 0) |
jjg@64 | 575 | return false; |
jjg@46 | 576 | |
jjg@46 | 577 | context.put(PrintWriter.class, log); |
jjg@46 | 578 | ClassWriter classWriter = ClassWriter.instance(context); |
jjg@283 | 579 | SourceWriter sourceWriter = SourceWriter.instance(context); |
jjg@283 | 580 | sourceWriter.setFileManager(fileManager); |
jjg@46 | 581 | |
jjg@346 | 582 | attributeFactory.setCompat(options.compat); |
jjg@346 | 583 | |
jjg@46 | 584 | boolean ok = true; |
jjg@46 | 585 | |
jjg@46 | 586 | for (String className: classes) { |
jjg@46 | 587 | JavaFileObject fo; |
jjg@46 | 588 | try { |
jjg@346 | 589 | writeClass(classWriter, className); |
jjg@46 | 590 | } catch (ConstantPoolException e) { |
jjg@340 | 591 | reportError("err.bad.constant.pool", className, e.getLocalizedMessage()); |
jjg@46 | 592 | ok = false; |
jjg@46 | 593 | } catch (EOFException e) { |
jjg@340 | 594 | reportError("err.end.of.file", className); |
jjg@46 | 595 | ok = false; |
jjg@46 | 596 | } catch (FileNotFoundException e) { |
jjg@340 | 597 | reportError("err.file.not.found", e.getLocalizedMessage()); |
jjg@46 | 598 | ok = false; |
jjg@46 | 599 | } catch (IOException e) { |
jjg@46 | 600 | //e.printStackTrace(); |
jjg@46 | 601 | Object msg = e.getLocalizedMessage(); |
jjg@46 | 602 | if (msg == null) |
jjg@46 | 603 | msg = e; |
jjg@340 | 604 | reportError("err.ioerror", className, msg); |
jjg@46 | 605 | ok = false; |
jjg@46 | 606 | } catch (Throwable t) { |
jjg@46 | 607 | StringWriter sw = new StringWriter(); |
jjg@46 | 608 | PrintWriter pw = new PrintWriter(sw); |
jjg@46 | 609 | t.printStackTrace(pw); |
jjg@46 | 610 | pw.close(); |
jjg@340 | 611 | reportError("err.crash", t.toString(), sw.toString()); |
jjg@52 | 612 | ok = false; |
jjg@46 | 613 | } |
jjg@46 | 614 | } |
jjg@46 | 615 | |
jjg@46 | 616 | return ok; |
jjg@46 | 617 | } |
jjg@46 | 618 | |
jjg@346 | 619 | protected boolean writeClass(ClassWriter classWriter, String className) |
jjg@346 | 620 | throws IOException, ConstantPoolException { |
jjg@350 | 621 | JavaFileObject fo = open(className); |
jjg@350 | 622 | if (fo == null) { |
jjg@350 | 623 | reportError("err.class.not.found", className); |
jjg@350 | 624 | return false; |
jjg@346 | 625 | } |
jjg@346 | 626 | |
jjg@346 | 627 | ClassFileInfo cfInfo = read(fo); |
jjg@346 | 628 | if (!className.endsWith(".class")) { |
jjg@346 | 629 | String cfName = cfInfo.cf.getName(); |
jjg@346 | 630 | if (!cfName.replaceAll("[/$]", ".").equals(className.replaceAll("[/$]", "."))) |
jjg@346 | 631 | reportWarning("warn.unexpected.class", className, cfName.replace('/', '.')); |
jjg@346 | 632 | } |
jjg@346 | 633 | write(cfInfo); |
jjg@346 | 634 | |
jjg@346 | 635 | if (options.showInnerClasses) { |
jjg@346 | 636 | ClassFile cf = cfInfo.cf; |
jjg@346 | 637 | Attribute a = cf.getAttribute(Attribute.InnerClasses); |
jjg@346 | 638 | if (a instanceof InnerClasses_attribute) { |
jjg@346 | 639 | InnerClasses_attribute inners = (InnerClasses_attribute) a; |
jjg@346 | 640 | try { |
jjg@346 | 641 | boolean ok = true; |
jjg@346 | 642 | for (int i = 0; i < inners.classes.length; i++) { |
jjg@346 | 643 | int outerIndex = inners.classes[i].outer_class_info_index; |
jjg@346 | 644 | ConstantPool.CONSTANT_Class_info outerClassInfo = cf.constant_pool.getClassInfo(outerIndex); |
jjg@346 | 645 | String outerClassName = outerClassInfo.getName(); |
jjg@346 | 646 | if (outerClassName.equals(cf.getName())) { |
jjg@346 | 647 | int innerIndex = inners.classes[i].inner_class_info_index; |
jjg@346 | 648 | ConstantPool.CONSTANT_Class_info innerClassInfo = cf.constant_pool.getClassInfo(innerIndex); |
jjg@346 | 649 | String innerClassName = innerClassInfo.getName(); |
jjg@346 | 650 | classWriter.println("// inner class " + innerClassName.replaceAll("[/$]", ".")); |
jjg@346 | 651 | classWriter.println(); |
jjg@346 | 652 | ok = ok & writeClass(classWriter, innerClassName); |
jjg@346 | 653 | } |
jjg@346 | 654 | } |
jjg@346 | 655 | return ok; |
jjg@346 | 656 | } catch (ConstantPoolException e) { |
jjg@346 | 657 | reportError("err.bad.innerclasses.attribute", className); |
jjg@346 | 658 | return false; |
jjg@346 | 659 | } |
jjg@346 | 660 | } else if (a != null) { |
jjg@346 | 661 | reportError("err.bad.innerclasses.attribute", className); |
jjg@346 | 662 | return false; |
jjg@346 | 663 | } |
jjg@346 | 664 | } |
jjg@346 | 665 | |
jjg@346 | 666 | return true; |
jjg@346 | 667 | } |
jjg@346 | 668 | |
jjg@350 | 669 | protected JavaFileObject open(String className) throws IOException { |
jjg@350 | 670 | // for compatibility, first see if it is a class name |
jjg@350 | 671 | JavaFileObject fo = getClassFileObject(className); |
jjg@350 | 672 | if (fo != null) |
jjg@350 | 673 | return fo; |
jjg@350 | 674 | |
jjg@350 | 675 | // see if it is an inner class, by replacing dots to $, starting from the right |
jjg@350 | 676 | String cn = className; |
jjg@350 | 677 | int lastDot; |
jjg@350 | 678 | while ((lastDot = cn.lastIndexOf(".")) != -1) { |
jjg@350 | 679 | cn = cn.substring(0, lastDot) + "$" + cn.substring(lastDot + 1); |
jjg@350 | 680 | fo = getClassFileObject(cn); |
jjg@350 | 681 | if (fo != null) |
jjg@350 | 682 | return fo; |
jjg@350 | 683 | } |
jjg@350 | 684 | |
jjg@350 | 685 | if (!className.endsWith(".class")) |
jjg@350 | 686 | return null; |
jjg@350 | 687 | |
jjg@350 | 688 | if (fileManager instanceof StandardJavaFileManager) { |
jjg@350 | 689 | StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager; |
jjg@350 | 690 | fo = sfm.getJavaFileObjects(className).iterator().next(); |
jjg@350 | 691 | if (fo != null && fo.getLastModified() != 0) { |
jjg@350 | 692 | return fo; |
jjg@350 | 693 | } |
jjg@350 | 694 | } |
jjg@350 | 695 | |
jjg@350 | 696 | // see if it is a URL, and if so, wrap it in just enough of a JavaFileObject |
jjg@350 | 697 | // to suit javap's needs |
jjg@350 | 698 | if (className.matches("^[A-Za-z]+:.*")) { |
jjg@350 | 699 | try { |
jjg@350 | 700 | final URI uri = new URI(className); |
jjg@350 | 701 | final URL url = uri.toURL(); |
jjg@350 | 702 | final URLConnection conn = url.openConnection(); |
jjg@350 | 703 | return new JavaFileObject() { |
jjg@350 | 704 | public Kind getKind() { |
jjg@350 | 705 | return JavaFileObject.Kind.CLASS; |
jjg@350 | 706 | } |
jjg@350 | 707 | |
jjg@350 | 708 | public boolean isNameCompatible(String simpleName, Kind kind) { |
jjg@350 | 709 | throw new UnsupportedOperationException(); |
jjg@350 | 710 | } |
jjg@350 | 711 | |
jjg@350 | 712 | public NestingKind getNestingKind() { |
jjg@350 | 713 | throw new UnsupportedOperationException(); |
jjg@350 | 714 | } |
jjg@350 | 715 | |
jjg@350 | 716 | public Modifier getAccessLevel() { |
jjg@350 | 717 | throw new UnsupportedOperationException(); |
jjg@350 | 718 | } |
jjg@350 | 719 | |
jjg@350 | 720 | public URI toUri() { |
jjg@350 | 721 | return uri; |
jjg@350 | 722 | } |
jjg@350 | 723 | |
jjg@350 | 724 | public String getName() { |
jjg@350 | 725 | return url.toString(); |
jjg@350 | 726 | } |
jjg@350 | 727 | |
jjg@350 | 728 | public InputStream openInputStream() throws IOException { |
jjg@350 | 729 | return conn.getInputStream(); |
jjg@350 | 730 | } |
jjg@350 | 731 | |
jjg@350 | 732 | public OutputStream openOutputStream() throws IOException { |
jjg@350 | 733 | throw new UnsupportedOperationException(); |
jjg@350 | 734 | } |
jjg@350 | 735 | |
jjg@350 | 736 | public Reader openReader(boolean ignoreEncodingErrors) throws IOException { |
jjg@350 | 737 | throw new UnsupportedOperationException(); |
jjg@350 | 738 | } |
jjg@350 | 739 | |
jjg@350 | 740 | public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { |
jjg@350 | 741 | throw new UnsupportedOperationException(); |
jjg@350 | 742 | } |
jjg@350 | 743 | |
jjg@350 | 744 | public Writer openWriter() throws IOException { |
jjg@350 | 745 | throw new UnsupportedOperationException(); |
jjg@350 | 746 | } |
jjg@350 | 747 | |
jjg@350 | 748 | public long getLastModified() { |
jjg@350 | 749 | return conn.getLastModified(); |
jjg@350 | 750 | } |
jjg@350 | 751 | |
jjg@350 | 752 | public boolean delete() { |
jjg@350 | 753 | throw new UnsupportedOperationException(); |
jjg@350 | 754 | } |
jjg@350 | 755 | |
jjg@350 | 756 | }; |
jjg@350 | 757 | } catch (URISyntaxException ignore) { |
jjg@350 | 758 | } catch (IOException ignore) { |
jjg@350 | 759 | } |
jjg@350 | 760 | } |
jjg@350 | 761 | |
jjg@350 | 762 | return null; |
jjg@350 | 763 | } |
jjg@350 | 764 | |
jjg@300 | 765 | public static class ClassFileInfo { |
jjg@300 | 766 | ClassFileInfo(JavaFileObject fo, ClassFile cf, byte[] digest, int size) { |
jjg@300 | 767 | this.fo = fo; |
jjg@300 | 768 | this.cf = cf; |
jjg@300 | 769 | this.digest = digest; |
jjg@300 | 770 | this.size = size; |
jjg@300 | 771 | } |
jjg@300 | 772 | public final JavaFileObject fo; |
jjg@300 | 773 | public final ClassFile cf; |
jjg@300 | 774 | public final byte[] digest; |
jjg@300 | 775 | public final int size; |
jjg@300 | 776 | } |
jjg@300 | 777 | |
jjg@300 | 778 | public ClassFileInfo read(JavaFileObject fo) throws IOException, ConstantPoolException { |
jjg@300 | 779 | InputStream in = fo.openInputStream(); |
jjg@300 | 780 | try { |
jjg@300 | 781 | SizeInputStream sizeIn = null; |
jjg@300 | 782 | MessageDigest md = null; |
jjg@300 | 783 | if (options.sysInfo || options.verbose) { |
jjg@300 | 784 | try { |
jjg@300 | 785 | md = MessageDigest.getInstance("MD5"); |
jjg@300 | 786 | } catch (NoSuchAlgorithmException ignore) { |
jjg@300 | 787 | } |
jjg@300 | 788 | in = new DigestInputStream(in, md); |
jjg@300 | 789 | in = sizeIn = new SizeInputStream(in); |
jjg@300 | 790 | } |
jjg@300 | 791 | |
jjg@300 | 792 | ClassFile cf = ClassFile.read(in, attributeFactory); |
jjg@300 | 793 | byte[] digest = (md == null) ? null : md.digest(); |
jjg@300 | 794 | int size = (sizeIn == null) ? -1 : sizeIn.size(); |
jjg@300 | 795 | return new ClassFileInfo(fo, cf, digest, size); |
jjg@300 | 796 | } finally { |
jjg@300 | 797 | in.close(); |
jjg@300 | 798 | } |
jjg@300 | 799 | } |
jjg@300 | 800 | |
jjg@300 | 801 | public void write(ClassFileInfo info) { |
jjg@300 | 802 | ClassWriter classWriter = ClassWriter.instance(context); |
jjg@300 | 803 | if (options.sysInfo || options.verbose) { |
jjg@300 | 804 | classWriter.setFile(info.fo.toUri()); |
jjg@300 | 805 | classWriter.setLastModified(info.fo.getLastModified()); |
jjg@300 | 806 | classWriter.setDigest("MD5", info.digest); |
jjg@300 | 807 | classWriter.setFileSize(info.size); |
jjg@300 | 808 | } |
jjg@300 | 809 | |
jjg@300 | 810 | classWriter.write(info.cf); |
jjg@300 | 811 | } |
jjg@300 | 812 | |
jjg@300 | 813 | protected void setClassFile(ClassFile classFile) { |
jjg@300 | 814 | ClassWriter classWriter = ClassWriter.instance(context); |
jjg@300 | 815 | classWriter.setClassFile(classFile); |
jjg@300 | 816 | } |
jjg@300 | 817 | |
jjg@300 | 818 | protected void setMethod(Method enclosingMethod) { |
jjg@300 | 819 | ClassWriter classWriter = ClassWriter.instance(context); |
jjg@300 | 820 | classWriter.setMethod(enclosingMethod); |
jjg@300 | 821 | } |
jjg@300 | 822 | |
jjg@300 | 823 | protected void write(Attribute value) { |
jjg@300 | 824 | AttributeWriter attrWriter = AttributeWriter.instance(context); |
jjg@300 | 825 | ClassWriter classWriter = ClassWriter.instance(context); |
jjg@300 | 826 | ClassFile cf = classWriter.getClassFile(); |
jjg@300 | 827 | attrWriter.write(cf, value, cf.constant_pool); |
jjg@300 | 828 | } |
jjg@300 | 829 | |
jjg@300 | 830 | protected void write(Attributes attrs) { |
jjg@300 | 831 | AttributeWriter attrWriter = AttributeWriter.instance(context); |
jjg@300 | 832 | ClassWriter classWriter = ClassWriter.instance(context); |
jjg@300 | 833 | ClassFile cf = classWriter.getClassFile(); |
jjg@300 | 834 | attrWriter.write(cf, attrs, cf.constant_pool); |
jjg@300 | 835 | } |
jjg@300 | 836 | |
jjg@300 | 837 | protected void write(ConstantPool constant_pool) { |
jjg@300 | 838 | ConstantWriter constantWriter = ConstantWriter.instance(context); |
jjg@300 | 839 | constantWriter.writeConstantPool(constant_pool); |
jjg@300 | 840 | } |
jjg@300 | 841 | |
jjg@300 | 842 | protected void write(ConstantPool constant_pool, int value) { |
jjg@300 | 843 | ConstantWriter constantWriter = ConstantWriter.instance(context); |
jjg@300 | 844 | constantWriter.write(value); |
jjg@300 | 845 | } |
jjg@300 | 846 | |
jjg@300 | 847 | protected void write(ConstantPool.CPInfo value) { |
jjg@300 | 848 | ConstantWriter constantWriter = ConstantWriter.instance(context); |
jjg@300 | 849 | constantWriter.println(value); |
jjg@300 | 850 | } |
jjg@300 | 851 | |
jjg@300 | 852 | protected void write(Field value) { |
jjg@300 | 853 | ClassWriter classWriter = ClassWriter.instance(context); |
jjg@300 | 854 | classWriter.writeField(value); |
jjg@300 | 855 | } |
jjg@300 | 856 | |
jjg@300 | 857 | protected void write(Method value) { |
jjg@300 | 858 | ClassWriter classWriter = ClassWriter.instance(context); |
jjg@300 | 859 | classWriter.writeMethod(value); |
jjg@300 | 860 | } |
jjg@300 | 861 | |
jjg@46 | 862 | private JavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) { |
jjg@402 | 863 | if (defaultFileManager == null) |
jjg@402 | 864 | defaultFileManager = JavapFileManager.create(dl, log); |
jjg@402 | 865 | return defaultFileManager; |
jjg@46 | 866 | } |
jjg@46 | 867 | |
jjg@46 | 868 | private JavaFileObject getClassFileObject(String className) throws IOException { |
jjg@46 | 869 | JavaFileObject fo; |
jjg@46 | 870 | fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS); |
jjg@46 | 871 | if (fo == null) |
jjg@46 | 872 | fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS); |
jjg@46 | 873 | return fo; |
jjg@46 | 874 | } |
jjg@46 | 875 | |
jjg@46 | 876 | private void showHelp() { |
jjg@46 | 877 | log.println(getMessage("main.usage", progname)); |
jjg@46 | 878 | for (Option o: recognizedOptions) { |
jjg@46 | 879 | String name = o.aliases[0].substring(1); // there must always be at least one name |
jjg@46 | 880 | if (name.startsWith("X") || name.equals("fullversion") || name.equals("h") || name.equals("verify")) |
jjg@46 | 881 | continue; |
jjg@46 | 882 | log.println(getMessage("main.opt." + name)); |
jjg@46 | 883 | } |
jjg@46 | 884 | String[] fmOptions = { "-classpath", "-bootclasspath" }; |
jjg@46 | 885 | for (String o: fmOptions) { |
jjg@46 | 886 | if (fileManager.isSupportedOption(o) == -1) |
jjg@46 | 887 | continue; |
jjg@46 | 888 | String name = o.substring(1); |
jjg@46 | 889 | log.println(getMessage("main.opt." + name)); |
jjg@46 | 890 | } |
jjg@46 | 891 | |
jjg@46 | 892 | } |
jjg@46 | 893 | |
jjg@46 | 894 | private void showVersion(boolean full) { |
jjg@46 | 895 | log.println(version(full ? "full" : "release")); |
jjg@46 | 896 | } |
jjg@46 | 897 | |
jjg@46 | 898 | private static final String versionRBName = "com.sun.tools.javap.resources.version"; |
jjg@46 | 899 | private static ResourceBundle versionRB; |
jjg@46 | 900 | |
jjg@46 | 901 | private String version(String key) { |
jjg@46 | 902 | // key=version: mm.nn.oo[-milestone] |
jjg@46 | 903 | // key=full: mm.mm.oo[-milestone]-build |
jjg@46 | 904 | if (versionRB == null) { |
jjg@46 | 905 | try { |
jjg@46 | 906 | versionRB = ResourceBundle.getBundle(versionRBName); |
jjg@46 | 907 | } catch (MissingResourceException e) { |
jjg@46 | 908 | return getMessage("version.resource.missing", System.getProperty("java.version")); |
jjg@46 | 909 | } |
jjg@46 | 910 | } |
jjg@46 | 911 | try { |
jjg@46 | 912 | return versionRB.getString(key); |
jjg@46 | 913 | } |
jjg@46 | 914 | catch (MissingResourceException e) { |
jjg@46 | 915 | return getMessage("version.unknown", System.getProperty("java.version")); |
jjg@46 | 916 | } |
jjg@46 | 917 | } |
jjg@46 | 918 | |
jjg@340 | 919 | private void reportError(String key, Object... args) { |
jjg@340 | 920 | diagnosticListener.report(createDiagnostic(Diagnostic.Kind.ERROR, key, args)); |
jjg@340 | 921 | } |
jjg@340 | 922 | |
jjg@340 | 923 | private void reportNote(String key, Object... args) { |
jjg@340 | 924 | diagnosticListener.report(createDiagnostic(Diagnostic.Kind.NOTE, key, args)); |
jjg@340 | 925 | } |
jjg@340 | 926 | |
jjg@340 | 927 | private void reportWarning(String key, Object... args) { |
jjg@340 | 928 | diagnosticListener.report(createDiagnostic(Diagnostic.Kind.WARNING, key, args)); |
jjg@340 | 929 | } |
jjg@340 | 930 | |
jjg@340 | 931 | private Diagnostic<JavaFileObject> createDiagnostic( |
jjg@340 | 932 | final Diagnostic.Kind kind, final String key, final Object... args) { |
jjg@46 | 933 | return new Diagnostic<JavaFileObject>() { |
jjg@46 | 934 | public Kind getKind() { |
jjg@340 | 935 | return kind; |
jjg@46 | 936 | } |
jjg@46 | 937 | |
jjg@46 | 938 | public JavaFileObject getSource() { |
jjg@46 | 939 | return null; |
jjg@46 | 940 | } |
jjg@46 | 941 | |
jjg@46 | 942 | public long getPosition() { |
jjg@46 | 943 | return Diagnostic.NOPOS; |
jjg@46 | 944 | } |
jjg@46 | 945 | |
jjg@46 | 946 | public long getStartPosition() { |
jjg@46 | 947 | return Diagnostic.NOPOS; |
jjg@46 | 948 | } |
jjg@46 | 949 | |
jjg@46 | 950 | public long getEndPosition() { |
jjg@46 | 951 | return Diagnostic.NOPOS; |
jjg@46 | 952 | } |
jjg@46 | 953 | |
jjg@46 | 954 | public long getLineNumber() { |
jjg@46 | 955 | return Diagnostic.NOPOS; |
jjg@46 | 956 | } |
jjg@46 | 957 | |
jjg@46 | 958 | public long getColumnNumber() { |
jjg@46 | 959 | return Diagnostic.NOPOS; |
jjg@46 | 960 | } |
jjg@46 | 961 | |
jjg@46 | 962 | public String getCode() { |
jjg@46 | 963 | return key; |
jjg@46 | 964 | } |
jjg@46 | 965 | |
jjg@46 | 966 | public String getMessage(Locale locale) { |
jjg@46 | 967 | return JavapTask.this.getMessage(locale, key, args); |
jjg@46 | 968 | } |
jjg@46 | 969 | |
jjg@346 | 970 | @Override |
jjg@340 | 971 | public String toString() { |
jjg@340 | 972 | return getClass().getName() + "[key=" + key + ",args=" + Arrays.asList(args) + "]"; |
jjg@340 | 973 | } |
jjg@340 | 974 | |
jjg@46 | 975 | }; |
jjg@46 | 976 | |
jjg@46 | 977 | } |
jjg@46 | 978 | |
jjg@283 | 979 | public String getMessage(String key, Object... args) { |
jjg@46 | 980 | return getMessage(task_locale, key, args); |
jjg@46 | 981 | } |
jjg@46 | 982 | |
jjg@283 | 983 | public String getMessage(Locale locale, String key, Object... args) { |
jjg@46 | 984 | if (bundles == null) { |
jjg@46 | 985 | // could make this a HashMap<Locale,SoftReference<ResourceBundle>> |
jjg@46 | 986 | // and for efficiency, keep a hard reference to the bundle for the task |
jjg@46 | 987 | // locale |
jjg@46 | 988 | bundles = new HashMap<Locale, ResourceBundle>(); |
jjg@46 | 989 | } |
jjg@46 | 990 | |
jjg@46 | 991 | if (locale == null) |
jjg@46 | 992 | locale = Locale.getDefault(); |
jjg@46 | 993 | |
jjg@46 | 994 | ResourceBundle b = bundles.get(locale); |
jjg@46 | 995 | if (b == null) { |
jjg@46 | 996 | try { |
jjg@46 | 997 | b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap", locale); |
jjg@46 | 998 | bundles.put(locale, b); |
jjg@46 | 999 | } catch (MissingResourceException e) { |
jjg@46 | 1000 | throw new InternalError("Cannot find javap resource bundle for locale " + locale); |
jjg@46 | 1001 | } |
jjg@46 | 1002 | } |
jjg@46 | 1003 | |
jjg@46 | 1004 | try { |
jjg@46 | 1005 | return MessageFormat.format(b.getString(key), args); |
jjg@46 | 1006 | } catch (MissingResourceException e) { |
jjg@46 | 1007 | throw new InternalError(e, key); |
jjg@46 | 1008 | } |
jjg@46 | 1009 | } |
jjg@46 | 1010 | |
jjg@300 | 1011 | protected Context context; |
jjg@46 | 1012 | JavaFileManager fileManager; |
jjg@402 | 1013 | JavaFileManager defaultFileManager; |
jjg@46 | 1014 | PrintWriter log; |
jjg@46 | 1015 | DiagnosticListener<? super JavaFileObject> diagnosticListener; |
jjg@46 | 1016 | List<String> classes; |
jjg@46 | 1017 | Options options; |
jjg@46 | 1018 | //ResourceBundle bundle; |
jjg@46 | 1019 | Locale task_locale; |
jjg@46 | 1020 | Map<Locale, ResourceBundle> bundles; |
jjg@300 | 1021 | protected Attribute.Factory attributeFactory; |
jjg@46 | 1022 | |
jjg@46 | 1023 | private static final String progname = "javap"; |
jjg@88 | 1024 | |
jjg@88 | 1025 | private static class SizeInputStream extends FilterInputStream { |
jjg@88 | 1026 | SizeInputStream(InputStream in) { |
jjg@88 | 1027 | super(in); |
jjg@88 | 1028 | } |
jjg@88 | 1029 | |
jjg@88 | 1030 | int size() { |
jjg@88 | 1031 | return size; |
jjg@88 | 1032 | } |
jjg@88 | 1033 | |
jjg@88 | 1034 | @Override |
jjg@88 | 1035 | public int read(byte[] buf, int offset, int length) throws IOException { |
jjg@88 | 1036 | int n = super.read(buf, offset, length); |
jjg@88 | 1037 | if (n > 0) |
jjg@88 | 1038 | size += n; |
jjg@88 | 1039 | return n; |
jjg@88 | 1040 | } |
jjg@88 | 1041 | |
jjg@88 | 1042 | @Override |
jjg@88 | 1043 | public int read() throws IOException { |
jjg@88 | 1044 | int b = super.read(); |
jjg@88 | 1045 | size += 1; |
jjg@88 | 1046 | return b; |
jjg@88 | 1047 | } |
jjg@88 | 1048 | |
jjg@88 | 1049 | private int size; |
jjg@88 | 1050 | } |
jjg@46 | 1051 | } |