Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

JRUBY-6867: Parsing issues with long lines

  • Loading branch information...
commit 4aa8812fb49935dabf5e93d143b7de9ad0b2636f 1 parent 99ce5c6
@enebo enebo authored
View
1  src/org/jruby/Main.java
@@ -59,7 +59,6 @@
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.SafePropertyAccessor;
import org.jruby.util.SimpleSampler;
-import org.jruby.util.cli.Options;
import org.jruby.util.cli.OutputStrings;
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;
View
82 src/org/jruby/RubyInstanceConfig.java
@@ -63,6 +63,7 @@
import org.jruby.runtime.load.LoadService;
import org.jruby.runtime.load.LoadService19;
import org.jruby.util.ClassCache;
+import org.jruby.util.InputStreamMarkCursor;
import org.jruby.util.JRubyFile;
import org.jruby.util.KCode;
import org.jruby.util.NormalizedFile;
@@ -220,16 +221,56 @@ public void tryProcessArgumentsWithRubyopts() {
// ignore and do nothing
}
}
+
+ // This method does not work like previous version in verifying it is
+ // a Ruby shebang line. Looking for ruby before \n is possible to add,
+ // but I wanted to keep this short.
+ private boolean isShebang(InputStreamMarkCursor cursor) throws IOException {
+ if (cursor.read() == '#') {
+ int c = cursor.read();
+ if (c == '!') {
+ cursor.endPoint(-2);
+ return true;
+ } else if (c == '\n') {
+ cursor.rewind();
+ }
+ } else {
+ cursor.rewind();
+ }
+
+ return false;
+ }
+
+ private boolean skipToNextLine(InputStreamMarkCursor cursor) throws IOException {
+ int c = cursor.read();
+ do {
+ if (c == '\n') return true;
+ } while ((c = cursor.read()) != -1);
+
+ return false;
+ }
+ private void eatToShebang(InputStream in) {
+ InputStreamMarkCursor cursor = new InputStreamMarkCursor(in, 8192);
+ try {
+ do {
+ if (isShebang(cursor)) break;
+ } while (skipToNextLine(cursor));
+ } catch (IOException e) {
+ } finally {
+ try { cursor.finish(); } catch (IOException e) {}
+ }
+ }
+
/**
* The intent here is to gather up any options that might have
* been specified in the shebang line and return them so they can
- * be merged into the ones specified on the commandline. This is
+ * be merged into the ones specified on the command-line. This is
* kind of a hopeless task because it's impossible to figure out
* where the command invocation stops and the parameters start.
* We try to work with the common scenarios where /usr/bin/env is
- * used to invoke the jruby shell script, and skip any parameters
- * it might have. Then we look for the interpreter invokation and
+ * used to invoke the JRuby shell script, and skip any parameters
+ * it might have. Then we look for the interpreter invocation and
* assume that the binary will have the word "ruby" in the name.
* This is error prone but should cover more cases than the
* previous code.
@@ -238,20 +279,21 @@ public void tryProcessArgumentsWithRubyopts() {
BufferedReader reader = null;
String[] result = new String[0];
if (in == null) return result;
+
+ if (isXFlag()) eatToShebang(in);
+
try {
- in.mark(1024);
+ InputStreamMarkCursor cursor = new InputStreamMarkCursor(in, 8192);
+ try {
+ if (!isShebang(cursor)) return result;
+ } finally {
+ cursor.finish();
+ }
+
+ in.mark(8192);
reader = new BufferedReader(new InputStreamReader(in, "iso-8859-1"), 8192);
String firstLine = reader.readLine();
- // Search for the shebang line in the given stream
- // if it wasn't found on the first line and the -x option
- // was specified
- if (isXFlag()) {
- while (firstLine != null && !isRubyShebangLine(firstLine)) {
- firstLine = reader.readLine();
- }
- }
-
boolean usesEnv = false;
if (firstLine.length() > 2 && firstLine.charAt(0) == '#' && firstLine.charAt(1) == '!') {
String[] options = firstLine.substring(2).split("\\s+");
@@ -263,17 +305,13 @@ public void tryProcessArgumentsWithRubyopts() {
continue;
}
// Skip any assignments if /usr/bin/env is in play
- if (usesEnv && options[i].indexOf('=') > 0) {
- continue;
- }
+ if (usesEnv && options[i].indexOf('=') > 0) continue;
+
// Skip any commandline args if /usr/bin/env is in play
- if (usesEnv && options[i].startsWith("-")) {
- continue;
- }
+ if (usesEnv && options[i].startsWith("-")) continue;
+
String basename = (new File(options[i])).getName();
- if (basename.indexOf("ruby") > 0) {
- break;
- }
+ if (basename.indexOf("ruby") > 0) break;
}
setHasShebangLine(true);
System.arraycopy(options, i, result, 0, options.length - i);
View
58 src/org/jruby/util/InputStreamMarkCursor.java
@@ -0,0 +1,58 @@
+package org.jruby.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Use mark to make a safe rewindable cursor. This assume you know
+ * the stream supports mark().
+ */
+public class InputStreamMarkCursor {
+ private InputStream in;
+ private int i = 0;
+ private int markSize;
+ private int actualReadTotal;
+ private byte[] buf;
+ private int endPoint = 0;
+
+ public InputStreamMarkCursor(InputStream in, int markSize) {
+ this.in = in;
+ this.markSize = markSize;
+ buf = new byte[0];
+ }
+
+ public int read() throws IOException {
+ if (buf.length == 0 || i > buf.length) { // overflow mark
+ if (buf.length != 0) {
+ in.reset(); // only reset if we have an active mark
+ }
+ buf = new byte[buf.length + markSize];
+ in.mark(buf.length + markSize);
+ actualReadTotal = in.read(buf, 0, buf.length);
+ }
+
+ return i >= actualReadTotal ? -1 : buf[i++];
+ }
+
+ public void endPoint(int delta) {
+ endPoint = i + delta;
+ }
+
+ public void rewind() {
+ i--;
+ }
+
+ /**
+ * reset back to mark and then read back to endPoint to repoint stream back
+ * to where we want next consumer of stream to start reading from.
+ */
+ public void finish() throws IOException {
+ in.reset();
+ buf = new byte[endPoint];
+ in.read(buf, 0, endPoint);
+ }
+
+ public void reset() throws IOException {
+ in.reset();
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.