19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.nashorn.tools;
27
28 import static jdk.nashorn.internal.runtime.Source.sourceFor;
29
30 import java.io.BufferedReader;
31 import java.io.File;
32 import java.io.FileReader;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.InputStreamReader;
36 import java.io.OutputStream;
37 import java.io.PrintStream;
38 import java.io.PrintWriter;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Locale;
42 import java.util.ResourceBundle;
43 import jdk.nashorn.api.scripting.NashornException;
44 import jdk.nashorn.internal.codegen.Compiler;
45 import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
46 import jdk.nashorn.internal.ir.Expression;
47 import jdk.nashorn.internal.ir.FunctionNode;
48 import jdk.nashorn.internal.ir.debug.ASTWriter;
49 import jdk.nashorn.internal.ir.debug.PrintVisitor;
50 import jdk.nashorn.internal.objects.Global;
51 import jdk.nashorn.internal.objects.NativeSymbol;
52 import jdk.nashorn.internal.parser.Parser;
53 import jdk.nashorn.internal.runtime.Context;
54 import jdk.nashorn.internal.runtime.ErrorManager;
55 import jdk.nashorn.internal.runtime.JSType;
56 import jdk.nashorn.internal.runtime.Property;
57 import jdk.nashorn.internal.runtime.ScriptEnvironment;
58 import jdk.nashorn.internal.runtime.ScriptFunction;
59 import jdk.nashorn.internal.runtime.ScriptObject;
60 import jdk.nashorn.internal.runtime.ScriptRuntime;
61 import jdk.nashorn.internal.runtime.Symbol;
62 import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
184 * @param out output stream for Shell
185 * @param err error stream for Shell
186 * @param args arguments to Shell
187 *
188 * @return null if there are problems with option parsing.
189 */
190 private static Context makeContext(final InputStream in, final OutputStream out, final OutputStream err, final String[] args) {
191 final PrintStream pout = out instanceof PrintStream ? (PrintStream) out : new PrintStream(out);
192 final PrintStream perr = err instanceof PrintStream ? (PrintStream) err : new PrintStream(err);
193 final PrintWriter wout = new PrintWriter(pout, true);
194 final PrintWriter werr = new PrintWriter(perr, true);
195
196 // Set up error handler.
197 final ErrorManager errors = new ErrorManager(werr);
198 // Set up options.
199 final Options options = new Options("nashorn", werr);
200
201 // parse options
202 if (args != null) {
203 try {
204 options.process(args);
205 } catch (final IllegalArgumentException e) {
206 werr.println(bundle.getString("shell.usage"));
207 options.displayHelp(e);
208 return null;
209 }
210 }
211
212 // detect scripting mode by any source's first character being '#'
213 if (!options.getBoolean("scripting")) {
214 for (final String fileName : options.getFiles()) {
215 final File firstFile = new File(fileName);
216 if (firstFile.isFile()) {
217 try (final FileReader fr = new FileReader(firstFile)) {
218 final int firstChar = fr.read();
219 // starts with '#
220 if (firstChar == '#') {
221 options.set("scripting", true);
222 break;
223 }
224 } catch (final IOException e) {
225 // ignore this. File IO errors will be reported later anyway
226 }
227 }
228 }
229 }
230
231 return new Context(options, errors, wout, werr, Thread.currentThread().getContextClassLoader());
232 }
233
234 /**
235 * Compiles the given script files in the command line
236 * This is called only when using the --compile-only flag
237 *
238 * @param context the nashorn context
239 * @param global the global scope
240 * @param files the list of script files to compile
241 *
242 * @return error code
243 * @throws IOException when any script file read results in I/O error
244 */
245 private static int compileScripts(final Context context, final Global global, final List<String> files) throws IOException {
246 final Global oldGlobal = Context.getGlobal();
247 final boolean globalChanged = (oldGlobal != global);
248 final ScriptEnvironment env = context.getEnv();
249 try {
250 if (globalChanged) {
251 Context.setGlobal(global);
252 }
253 final ErrorManager errors = context.getErrorManager();
254
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.nashorn.tools;
27
28 import static jdk.nashorn.internal.runtime.Source.sourceFor;
29
30 import java.io.BufferedReader;
31 import java.io.File;
32 import java.io.FileReader;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.InputStreamReader;
36 import java.io.OutputStream;
37 import java.io.PrintStream;
38 import java.io.PrintWriter;
39 import java.nio.file.Files;
40 import java.nio.file.Path;
41 import java.nio.file.Paths;
42 import java.util.*;
43 import java.util.stream.Collectors;
44
45 import jdk.nashorn.api.scripting.NashornException;
46 import jdk.nashorn.internal.codegen.Compiler;
47 import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
48 import jdk.nashorn.internal.ir.Expression;
49 import jdk.nashorn.internal.ir.FunctionNode;
50 import jdk.nashorn.internal.ir.debug.ASTWriter;
51 import jdk.nashorn.internal.ir.debug.PrintVisitor;
52 import jdk.nashorn.internal.objects.Global;
53 import jdk.nashorn.internal.objects.NativeSymbol;
54 import jdk.nashorn.internal.parser.Parser;
55 import jdk.nashorn.internal.runtime.Context;
56 import jdk.nashorn.internal.runtime.ErrorManager;
57 import jdk.nashorn.internal.runtime.JSType;
58 import jdk.nashorn.internal.runtime.Property;
59 import jdk.nashorn.internal.runtime.ScriptEnvironment;
60 import jdk.nashorn.internal.runtime.ScriptFunction;
61 import jdk.nashorn.internal.runtime.ScriptObject;
62 import jdk.nashorn.internal.runtime.ScriptRuntime;
63 import jdk.nashorn.internal.runtime.Symbol;
64 import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
186 * @param out output stream for Shell
187 * @param err error stream for Shell
188 * @param args arguments to Shell
189 *
190 * @return null if there are problems with option parsing.
191 */
192 private static Context makeContext(final InputStream in, final OutputStream out, final OutputStream err, final String[] args) {
193 final PrintStream pout = out instanceof PrintStream ? (PrintStream) out : new PrintStream(out);
194 final PrintStream perr = err instanceof PrintStream ? (PrintStream) err : new PrintStream(err);
195 final PrintWriter wout = new PrintWriter(pout, true);
196 final PrintWriter werr = new PrintWriter(perr, true);
197
198 // Set up error handler.
199 final ErrorManager errors = new ErrorManager(werr);
200 // Set up options.
201 final Options options = new Options("nashorn", werr);
202
203 // parse options
204 if (args != null) {
205 try {
206 final String[] prepArgs = preprocessArgs(args);
207 options.process(prepArgs);
208 } catch (final IllegalArgumentException e) {
209 werr.println(bundle.getString("shell.usage"));
210 options.displayHelp(e);
211 return null;
212 }
213 }
214
215 // detect scripting mode by any source's first character being '#'
216 if (!options.getBoolean("scripting")) {
217 for (final String fileName : options.getFiles()) {
218 final File firstFile = new File(fileName);
219 if (firstFile.isFile()) {
220 try (final FileReader fr = new FileReader(firstFile)) {
221 final int firstChar = fr.read();
222 // starts with '#
223 if (firstChar == '#') {
224 options.set("scripting", true);
225 break;
226 }
227 } catch (final IOException e) {
228 // ignore this. File IO errors will be reported later anyway
229 }
230 }
231 }
232 }
233
234 return new Context(options, errors, wout, werr, Thread.currentThread().getContextClassLoader());
235 }
236
237 /**
238 * Preprocess the command line arguments passed in by the shell. This checks, for each of the arguments, whether it
239 * can be a file name, and if so, whether the file exists. If the file exists and begins with a shebang line, and
240 * the arguments on that line are a prefix of {@code args} with the file removed, it is assumed that a script file
241 * being executed via shebang was found, and it is moved to the appropriate position in the argument list. The first
242 * such match is used.
243 * <p>
244 * This method canonicalizes the command line arguments to the form {@code <options> <scripts> -- <arguments>},
245 * where the last of the {@code scripts} is the one being run in shebang fashion.
246 *
247 * @param args the command line arguments as passed into Nashorn.
248 * @return a properly ordered argument list
249 */
250 private static String[] preprocessArgs(final String[] args) {
251 final List<String> largs = new ArrayList<>();
252 Collections.addAll(largs, args);
253 final List<String> pa = new ArrayList<>();
254 String scriptFile = null;
255 boolean found = false;
256 for (int i = 0; i < args.length; ++i) {
257 final String a = args[i];
258 final Path p = Paths.get(a);
259 if (!found && (!a.startsWith("-") || a.length() == 1) && Files.exists(p)) {
260 String l = "";
261 try (final BufferedReader r = Files.newBufferedReader(p)) {
262 l = r.readLine();
263 } catch (IOException ioe) {
264 // ignore
265 }
266 if (l.startsWith("#!")) {
267 List<String> shebangArgs = Arrays.asList(l.split(" "));
268 shebangArgs = shebangArgs.subList(1, shebangArgs.size()); // remove #! part
269 final int ssize = shebangArgs.size();
270 final List<String> filteredArgs = largs.stream().filter(x -> !x.equals(a)).collect(Collectors.toList());
271 if (filteredArgs.size() >= ssize && shebangArgs.equals(filteredArgs.subList(0, ssize))) {
272 scriptFile = a;
273 found = true;
274 continue;
275 }
276 }
277 }
278 pa.add(a);
279 }
280 if (scriptFile != null) {
281 // Insert the found script file name either before a -- argument, or at the end of the options list, before
282 // any other arguments, with an extra --.
283 int argidx = pa.indexOf("--");
284 if (argidx == -1) {
285 for (String s : pa) {
286 ++argidx;
287 if (s.charAt(0) != '-') {
288 pa.add(argidx, "--");
289 break;
290 }
291 }
292 }
293 pa.add(argidx, scriptFile);
294 }
295 return pa.stream().toArray(String[]::new);
296 }
297
298 /**
299 * Compiles the given script files in the command line
300 * This is called only when using the --compile-only flag
301 *
302 * @param context the nashorn context
303 * @param global the global scope
304 * @param files the list of script files to compile
305 *
306 * @return error code
307 * @throws IOException when any script file read results in I/O error
308 */
309 private static int compileScripts(final Context context, final Global global, final List<String> files) throws IOException {
310 final Global oldGlobal = Context.getGlobal();
311 final boolean globalChanged = (oldGlobal != global);
312 final ScriptEnvironment env = context.getEnv();
313 try {
314 if (globalChanged) {
315 Context.setGlobal(global);
316 }
317 final ErrorManager errors = context.getErrorManager();
318
|