Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Port of the "slow" logic for gets, down to the letter. The fast port …

…may come later, but I'm going for correctness right now.

git-svn-id: http://svn.codehaus.org/jruby/branches/headius_io@5805 961051c9-f516-0410-bf72-c9f7e237a7b7
  • Loading branch information...
commit 6c093a953550aec45e2e1a7411ca422210cd6373 1 parent 4f5b85f
Charles Oliver Nutter headius authored
165 src/org/jruby/RubyIO.java
View
@@ -581,31 +581,89 @@ private ByteList getSeparatorForGets(IRubyObject[] args) {
return separator;
}
- /** Read a line.
- *
- */
- // TODO: Most things loop over this and always pass it the same arguments
- // meaning they are an invariant of the loop. Think about fixing this.
- public IRubyObject getline(IRubyObject[] args) {
- return getline(getSeparatorForGets(args));
- }
-
public IRubyObject getline(ByteList separator) {
try {
openFile.checkReadable(getRuntime());
-
- ByteList newLine = openFile.getMainStream().fgets(separator);
+ boolean isParagraph = separator == Stream.PARAGRAPH_DELIMETER;
+
+ if (isParagraph) {
+ swallow('\n');
+ }
+
+ if (separator == null) {
+ IRubyObject str = readAll(null);
+ if (((RubyString)str).getByteList().length() == 0) {
+ return getRuntime().getNil();
+ }
+ return str;
+ } else if (separator.length() == 1) {
+ return getlineFast(separator.get(0));
+ } else {
+ Stream readStream = openFile.getMainStream();
+ int c = -1;
+ int newline = separator.get(separator.length() - 1);
- if (newLine != null) {
- openFile.setLineNumber(openFile.getLineNumber() + 1);
- getRuntime().getGlobalVariables().set("$.", getRuntime().newFixnum(openFile.getLineNumber()));
- RubyString result = RubyString.newString(getRuntime(), newLine);
- result.taint();
+ ByteList buf = new ByteList(1024);
+ boolean update = false;
+
+ while (true) {
+ do {
+ readCheck(readStream);
+ readStream.clearerr();
+
+ try {
+ c = readStream.fgetc();
+ } catch (EOFException e) {
+ c = -1;
+ }
+
+ if (c == -1) {
+ // TODO: clear error, wait for it to become readable
+ if (c == -1) {
+ if (update) {
+ return RubyString.newString(getRuntime(), buf);
+ }
+ break;
+ }
+ }
+
+ buf.append(c);
+
+ update = true;
+ } while (c != newline); // loop until we see the nth separator char
+
+ // if we hit EOF, we're done
+ if (c == -1) {
+ break;
+ }
+
+ // if we've found the last char of the separator,
+ // and we've found at least as many characters as separator length,
+ // and the last n characters of our buffer match the separator, we're done
+ if (c == newline && buf.length() >= separator.length() &&
+ 0 == ByteList.memcmp(buf.unsafeBytes(), buf.begin + buf.realSize - separator.length(), separator.unsafeBytes(), separator.begin, separator.realSize)) {
+ break;
+ }
+ }
+
+ if (isParagraph) {
+ if (c != -1) {
+ swallow('\n');
+ }
+ }
+
+ if (!update) {
+ return getRuntime().getNil();
+ } else {
+ openFile.setLineNumber(openFile.getLineNumber() + 1);
+ // this is for a range check, near as I can tell
+ RubyNumeric.int2fix(getRuntime(), openFile.getLineNumber());
+ RubyString str = RubyString.newString(getRuntime(), buf);
+ str.setTaint(true);
- return result;
+ return str;
+ }
}
-
- return getRuntime().getNil();
} catch (PipeException ex) {
throw getRuntime().newErrnoEPIPEError();
} catch (InvalidValueException ex) {
@@ -618,6 +676,71 @@ public IRubyObject getline(ByteList separator) {
throw getRuntime().newIOError(e.getMessage());
}
}
+
+ protected boolean swallow(int term) throws IOException, BadDescriptorException {
+ Stream readStream = openFile.getMainStream();
+ int c;
+
+ do {
+ readCheck(readStream);
+
+ try {
+ c = readStream.fgetc();
+ } catch (EOFException e) {
+ c = -1;
+ }
+
+ if (c != term) {
+ return true;
+ }
+ } while (c != -1);
+
+ return false;
+ }
+
+ public IRubyObject getlineFast(int delim) throws IOException, BadDescriptorException {
+ Stream readStream = openFile.getMainStream();
+ int c = -1;
+
+ ByteList buf = new ByteList(1024);
+ boolean update = false;
+ do {
+ readCheck(readStream);
+ readStream.clearerr();
+
+ try {
+ c = readStream.fgetc();
+ } catch (EOFException e) {
+ c = -1;
+ }
+
+ if (c == -1) {
+ // TODO: clear error, wait for it to become readable
+ if (c == -1) {
+ if (update) {
+ return RubyString.newString(getRuntime(), buf);
+ }
+ break;
+ }
+ }
+
+ buf.append(c);
+
+ update = true;
+ } while (c != delim);
+
+ if (!update) {
+ return getRuntime().getNil();
+ } else {
+ openFile.setLineNumber(openFile.getLineNumber() + 1);
+ // this is for a range check, near as I can tell
+ RubyNumeric.int2fix(getRuntime(), openFile.getLineNumber());
+ RubyString str = RubyString.newString(getRuntime(), buf);
+ str.setTaint(true);
+
+ return str;
+ }
+ }
// IO class methods.
@JRubyMethod(name = {"new"}, rest = true, frame = true, meta = true)
@@ -1456,7 +1579,9 @@ public RubyIO flush() {
*/
@JRubyMethod(name = "gets", optional = 1)
public IRubyObject gets(IRubyObject[] args) {
- IRubyObject result = getline(args);
+ ByteList separator = getSeparatorForGets(args);
+
+ IRubyObject result = getline(separator);
if (!result.isNil()) getRuntime().getCurrentContext().getCurrentFrame().setLastLine(result);
11 src/org/jruby/util/ByteList.java
View
@@ -730,4 +730,15 @@ public static int memcmp(final byte[] first, final int firstStart, final int fir
return firstLen == secondLen ? 0 : firstLen == len ? -1 : 1;
}
+
+ public static int memcmp(final byte[] first, final int firstStart, final byte[] second, final int secondStart, final int len) {
+ if (first == second) return 0;
+ int offset = -1;
+ for ( ; ++offset < len && first[firstStart + offset] == second[secondStart + offset]; ) ;
+ if (offset < len) {
+ return (first[firstStart + offset]&0xFF) > (second[secondStart + offset]&0xFF) ? 1 : -1;
+ }
+ return 0;
+
+ }
}
14 src/org/jruby/util/io/ChannelStream.java
View
@@ -561,7 +561,10 @@ private int bufferedRead() throws IOException, BadDescriptorException {
int read = descriptor.read(buffer);
buffer.flip();
- if (read <= 0) return -1;
+ if (read <= 0) {
+ eof = true;
+ return -1;
+ }
}
return buffer.get() & 0xFF;
}
@@ -675,13 +678,19 @@ public void ungetc(int c) {
}
public synchronized int fgetc() throws IOException, BadDescriptorException {
+ if (eof) {
+ return -1;
+ }
+
checkReadable();
int c = read();
if (c == -1) {
+ eof = true;
return c;
}
+
return c & 0xff;
}
@@ -739,7 +748,8 @@ public synchronized int read() throws IOException, BadDescriptorException {
}
return bufferedRead();
- } catch (EOFException eof) {
+ } catch (EOFException e) {
+ eof = true;
return -1;
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.