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 }