1 /* 2 * Copyright (c) 1996, 2019, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.openjdk.asmtools.jasm; 24 25 import static org.openjdk.asmtools.jasm.CFVersion.DEFAULT_MAJOR_VERSION; 26 import static org.openjdk.asmtools.jasm.CFVersion.DEFAULT_MINOR_VERSION; 27 28 import org.openjdk.asmtools.common.Tool; 29 import org.openjdk.asmtools.util.I18NResourceBundle; 30 import org.openjdk.asmtools.util.ProductInfo; 31 32 import java.io.*; 33 import java.util.ArrayList; 34 35 /** 36 * 37 * 38 */ 39 public class Main extends Tool { 40 41 public static final I18NResourceBundle i18n 42 = I18NResourceBundle.getBundleForClass(Main.class); 43 44 private File destDir = null; 45 private boolean traceFlag = false; 46 private long tm = System.currentTimeMillis(); 47 private ArrayList<String> v = new ArrayList<>(); 48 private boolean nowrite = false; 49 private boolean nowarn = false; 50 private boolean strict = false; 51 private String props = null; 52 private int nwarnings = 0; 53 private CFVersion cfv = new CFVersion(); 54 private int bytelimit = 0; 55 private boolean debugScanner = false; 56 private boolean debugMembers = false; 57 private boolean debugCP = false; 58 private boolean debugAnnot = false; 59 private boolean debugInstr = false; 60 61 62 public Main(PrintWriter out, String programName) { 63 super(out, programName); 64 printCannotReadMsg = (fname) -> 65 error( i18n.getString("jasm.error.cannot_read", fname)); 66 } 67 68 public Main(PrintStream out, String program) { 69 this(new PrintWriter(out), program); 70 } 71 72 @Override 73 public void usage() { 74 println(i18n.getString("jasm.usage")); 75 println(i18n.getString("jasm.opt.d")); 76 println(i18n.getString("jasm.opt.g")); 77 println(i18n.getString("jasm.opt.v")); 78 println(i18n.getString("jasm.opt.nowrite")); 79 println(i18n.getString("jasm.opt.nowarn")); 80 println(i18n.getString("jasm.opt.strict")); 81 println(i18n.getString("jasm.opt.cv", DEFAULT_MAJOR_VERSION, DEFAULT_MINOR_VERSION)); 82 println(i18n.getString("jasm.opt.version")); 83 } 84 85 /** 86 * Run the compiler 87 */ 88 private synchronized boolean parseArgs(String argv[]) { 89 // Parse arguments 90 boolean frozenCFV = false; 91 for (int i = 0; i < argv.length; i++) { 92 String arg = argv[i]; 93 switch (arg) { 94 case "-v": 95 traceFlag = true; 96 break; 97 case "-g": 98 super.DebugFlag = () -> true; 99 break; 100 case "-nowrite": 101 nowrite = true; 102 break; 103 case "-strict": 104 strict = true; 105 break; 106 case "-nowarn": 107 nowarn = true; 108 break; 109 case "-version": 110 println(ProductInfo.FULL_VERSION); 111 break; 112 case "-d": 113 if ((i + 1) >= argv.length) { 114 error(i18n.getString("jasm.error.d_requires_argument")); 115 usage(); 116 return false; 117 } 118 destDir = new File(argv[++i]); 119 if (!destDir.exists()) { 120 error(i18n.getString("jasm.error.does_not_exist", destDir.getPath())); 121 return false; 122 } 123 break; 124 // non-public options 125 case "-XdScanner": 126 debugScanner = true; 127 break; 128 case "-XdMember": 129 debugMembers = true; 130 break; 131 case "-XdCP": 132 debugCP = true; 133 break; 134 case "-XdInstr": 135 debugInstr = true; 136 break; 137 case "-XdAnnot": 138 debugAnnot = true; 139 break; 140 case "-XdAll": 141 debugScanner = true; 142 debugMembers = true; 143 debugCP = true; 144 debugInstr = true; 145 debugAnnot = true; 146 break; 147 case "-Xdlimit": 148 // parses file until the specified byte number 149 if (i + 1 > argv.length) { 150 println(" Error: Unspecified byte-limit"); 151 return false; 152 } else { 153 i++; 154 String bytelimstr = argv[i]; 155 bytelimit = 0; 156 try { 157 bytelimit = Integer.parseInt(bytelimstr); 158 } catch (NumberFormatException e) { 159 println(" Error: Unspecified byte-limit"); 160 return false; 161 } 162 } 163 break; 164 case "-fixcv": 165 // overrides cf version if it's defined in the source file. 166 frozenCFV = true; 167 // public options 168 case "-cv": 169 if ((i + 1) >= argv.length) { 170 error(i18n.getString("jasm.error.cv_requires_arg")); 171 usage(); 172 return false; 173 } 174 String[] versions = {"", ""}; // workaround for String.split() 175 int index = argv[++i].indexOf("."); // 176 if (index != -1) { // 177 versions[0] = argv[i].substring(0, index); // 178 versions[1] = argv[i].substring(index + 1); // 179 } // 180 if (versions.length != 2) { 181 error(i18n.getString("jasm.error.invalid_major_minor_param")); 182 usage(); 183 return false; 184 } 185 try { 186 cfv = new CFVersion(frozenCFV, Short.parseShort(versions[0]), Short.parseShort(versions[1]) ); 187 } catch (NumberFormatException e) { 188 error(i18n.getString("jasm.error.invalid_major_minor_param")); 189 usage(); 190 return false; 191 } 192 break; 193 default: 194 if (arg.startsWith("-")) { 195 error(i18n.getString("jasm.error.invalid_option", arg)); 196 usage(); 197 return false; 198 } else { 199 v.add(argv[i]); 200 } 201 break; 202 } 203 } 204 if (v.size() == 0) { 205 usage(); 206 return false; 207 } 208 if (strict) { 209 nowarn = false; 210 } 211 return true; 212 } 213 214 private void reset() { 215 destDir = null; 216 traceFlag = false; 217 super.DebugFlag = () -> false; 218 System.currentTimeMillis(); 219 v = new ArrayList<>(); 220 nowrite = false; 221 nowarn = false; 222 strict = false; 223 props = null; 224 nwarnings = 0; 225 bytelimit = 0; 226 } 227 228 /** 229 * Run the compiler 230 */ 231 public synchronized boolean compile(String argv[]) { 232 // Reset the state of all objs 233 reset(); 234 235 boolean validArgs = parseArgs(argv); 236 if (!validArgs) { 237 return false; 238 } 239 // compile all input files 240 Environment sf = null; 241 try { 242 for (String inpname : v) { 243 Parser p; 244 245 DataInputStream dataInputStream = getDataInputStream(inpname); 246 if( dataInputStream == null ) { 247 nerrors++; 248 continue; 249 } 250 sf = new Environment(dataInputStream, inpname, out, nowarn); 251 sf.traceFlag = traceFlag; 252 sf.debugInfoFlag = DebugFlag.getAsBoolean(); 253 p = new Parser(sf, cfv.clone() ); 254 p.setDebugFlags(debugScanner, debugMembers, debugCP, debugAnnot, debugInstr); 255 p.parseFile(); 256 257 nerrors += sf.nerrors; 258 nwarnings += sf.nwarnings; 259 if (nowrite || (nerrors > 0)) { 260 sf.flushErrors(); 261 continue; 262 } 263 try { 264 ClassData[] clsData = p.getClassesData(); 265 for (int i = 0; i < clsData.length; i++) { 266 ClassData cd = clsData[i]; 267 if (bytelimit > 0) { 268 cd.setByteLimit(bytelimit); 269 } 270 cd.write(destDir); 271 } 272 } catch (IOException ex) { 273 if (bytelimit > 0) { 274 // IO Error thrown from user-specified byte count 275 ex.printStackTrace(); 276 error("UserSpecified byte-limit at byte[" + bytelimit + "]: " + 277 ex.getMessage() + "\n" + 278 inpname + ": [" + sf.lineNumber() + ", " + sf.lineOffset() + "]"); 279 } else { 280 String er = i18n.getString("jasm.error.cannot_write", ex.getMessage()); 281 error(er + "\n" + inpname + ": [" + sf.lineNumber() + ", " + sf.lineOffset() + "]"); 282 } 283 } 284 sf.flushErrors(); // possible errors from write() 285 } 286 } catch (Error ee) { 287 if (DebugFlag.getAsBoolean()) { 288 ee.printStackTrace(); 289 } 290 String er = ee.getMessage() + "\n" + i18n.getString("jasm.error.fatal_error"); 291 error(er + "\n" + sf.getInputFileName() + ": [" + sf.lineNumber() + ", " + sf.lineOffset() + "]"); 292 } catch (Exception ee) { 293 if (DebugFlag.getAsBoolean()) { 294 ee.printStackTrace(); 295 } 296 String er = ee.getMessage() + "\n" + ee.getMessage() + "\n" + i18n.getString("jasm.error.fatal_exception"); 297 error(er + "\n" + sf.getInputFileName() + ": [" + sf.lineNumber() + ", " + sf.lineOffset() + "]"); 298 } 299 300 boolean errs = nerrors > 0; 301 boolean warns = (nwarnings > 0) && (!nowarn); 302 boolean errsOrWarns = errs || warns; 303 if (!errsOrWarns) { 304 return true; 305 } 306 if (errs) { 307 out.print(nerrors > 1 ? (nerrors + " errors") : "1 error"); 308 } 309 if (errs && warns) { 310 out.print(", "); 311 } 312 if (warns) { 313 out.print(nwarnings > 1 ? (nwarnings + " warnings") : "1 warning"); 314 } 315 println(); 316 if (strict) { 317 return !errsOrWarns; 318 } else { 319 return !errs; 320 } 321 } 322 323 /** 324 * main program 325 */ 326 public static void main(String argv[]) { 327 Main compiler = new Main(new PrintWriter(System.out), "jasm"); 328 System.exit(compiler.compile(argv) ? 0 : 1); 329 } 330 }