1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* ext/stringio/stringio.c (strio_gets): accepts limit argument.

* ext/stringio/stringio.c (strio_readline, strio_each,
  strio_readlines): ditto.

* ext/stringio/stringio.c (strio_getline): add limit capability.

* io.c (rb_io_gets_m): accepts limit argument.  [ruby-talk:231563]

* io.c (rb_io_readline, rb_io_readlines, rb_io_each_line, argf_getline):
  ditto.

* io.c (appendline): add limit capability.

* io.c (rb_io_getline_fast, rb_io_getline): ditto.

* io.c (rb_io_getline): small refactoring for DRY.

* io.c (rb_io_s_foreach, rb_io_s_readlines): small refactoring.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11428 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 2006-12-29 19:21:50 +00:00
parent 0d2e0eb6cb
commit 424f8ec44f
4 changed files with 198 additions and 110 deletions

View file

@ -1,3 +1,27 @@
Sat Dec 30 02:54:22 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
* ext/stringio/stringio.c (strio_gets): accepts limit argument.
* ext/stringio/stringio.c (strio_readline, strio_each,
strio_readlines): ditto.
Sat Dec 30 02:22:32 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
* ext/stringio/stringio.c (strio_getline): add limit capability.
* io.c (rb_io_gets_m): accepts limit argument. [ruby-talk:231563]
* io.c (rb_io_readline, rb_io_readlines, rb_io_each_line, argf_getline):
ditto.
* io.c (appendline): add limit capability.
* io.c (rb_io_getline_fast, rb_io_getline): ditto.
* io.c (rb_io_getline): small refactoring for DRY.
* io.c (rb_io_s_foreach, rb_io_s_readlines): small refactoring.
Thu Dec 28 15:27:38 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
* lib/cgi.rb (CGI::Cookie::initialize): use Array() again.

View file

@ -766,15 +766,33 @@ static VALUE
strio_getline(int argc, VALUE *argv, struct StringIO *ptr)
{
const char *s, *e, *p;
long n;
long n, limit;
VALUE str;
if (argc == 0) {
str = rb_rs;
limit = 0;
}
else {
rb_scan_args(argc, argv, "1", &str);
if (!NIL_P(str)) StringValue(str);
VALUE lim, tmp;
rb_scan_args(argc, argv, "11", &str, &lim);
if (!NIL_P(lim)) limit = NUM2LONG(lim);
else if (!NIL_P(str) && TYPE(str) != T_STRING) {
tmp = rb_check_string_type(str);
if (NIL_P(tmp)) {
limit = NUM2LONG(str);
if (limit == 0) return rb_str_new(0,0);
str = rb_rs;
}
else {
str = tmp;
limit = 0;
}
}
else {
StringValue(str);
}
}
if (ptr->pos >= (n = RSTRING_LEN(ptr->string))) {
@ -783,6 +801,9 @@ strio_getline(int argc, VALUE *argv, struct StringIO *ptr)
s = RSTRING_PTR(ptr->string);
e = s + RSTRING_LEN(ptr->string);
s += ptr->pos;
if (limit > 0 && s + limit < e) {
e = s + limit;
}
if (NIL_P(str)) {
str = rb_str_substr(ptr->string, ptr->pos, e - s);
}
@ -836,7 +857,9 @@ strio_getline(int argc, VALUE *argv, struct StringIO *ptr)
/*
* call-seq:
* strio.gets(sep_string=$/) -> string or nil
* strio.gets(sep=$/) -> string or nil
* strio.gets(limit) -> string or nil
* strio.gets(sep, limit) -> string or nil
*
* See IO#gets.
*/
@ -851,7 +874,9 @@ strio_gets(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
* strio.readline(sep_string=$/) -> string
* strio.readline(sep=$/) -> string
* strio.readline(limit) -> string or nil
* strio.readline(sep, limit) -> string or nil
*
* See IO#readline.
*/
@ -865,8 +890,12 @@ strio_readline(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
* strio.each(sep_string=$/) {|line| block } -> strio
* strio.each_line(sep_string=$/) {|line| block } -> strio
* strio.each(sep=$/) {|line| block } -> strio
* strio.each(limit) {|line| block } -> strio
* strio.each(sep, limit) {|line| block } -> strio
* strio.each_line(sep=$/) {|line| block } -> strio
* strio.each_line(limit) {|line| block } -> strio
* strio.each_line(sep,limit) {|line| block } -> strio
*
* See IO#each.
*/
@ -884,7 +913,9 @@ strio_each(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
* strio.readlines(sep_string=$/) -> array
* strio.readlines(sep=$/) -> array
* strio.readlines(limit) -> array
* strio.readlines(sep,limit) -> array
*
* See IO#readlines.
*/

223
io.c
View file

@ -1535,17 +1535,21 @@ io_read(int argc, VALUE *argv, VALUE io)
}
static int
appendline(OpenFile *fptr, int delim, VALUE *strp)
appendline(OpenFile *fptr, int delim, VALUE *strp, long *lp)
{
VALUE str = *strp;
int c = EOF;
long limit = *lp;
do {
long pending = READ_DATA_PENDING_COUNT(fptr);
if (pending > 0) {
const char *p = READ_DATA_PENDING_PTR(fptr);
const char *e = memchr(p, delim, pending);
const char *e;
long last = 0, len = (c != EOF);
if (limit > 0 && pending > limit) pending = limit;
e = memchr(p, delim, pending);
if (e) pending = e - p + 1;
len += pending;
if (!NIL_P(str)) {
@ -1560,6 +1564,9 @@ appendline(OpenFile *fptr, int delim, VALUE *strp)
RSTRING_PTR(str)[last++] = c;
}
read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
limit -= pending;
*lp = limit;
if (limit == 0) return RSTRING_PTR(str)[RSTRING_LEN(str)-1];
if (e) return delim;
}
else if (c != EOF) {
@ -1576,7 +1583,9 @@ appendline(OpenFile *fptr, int delim, VALUE *strp)
rb_thread_wait_fd(fptr->fd);
rb_io_check_closed(fptr);
c = io_getc(fptr);
limit--;
if (c < 0) {
*lp = limit;
return c;
}
} while (c != delim);
@ -1624,16 +1633,21 @@ swallow(OpenFile *fptr, int term)
}
static VALUE
rb_io_getline_fast(OpenFile *fptr, unsigned char delim)
rb_io_getline_fast(OpenFile *fptr, unsigned char delim, long limit)
{
VALUE str = Qnil;
int c;
while ((c = appendline(fptr, delim, &str)) != EOF && c != delim);
for (;;) {
c = appendline(fptr, delim, &str, &limit);
if (c == EOF || c == delim || limit == 0) break;
}
if (!NIL_P(str)) {
if (limit > 0) {
fptr->lineno++;
lineno = INT2FIX(fptr->lineno);
}
OBJ_TAINT(str);
}
@ -1649,10 +1663,31 @@ rscheck(const char *rsptr, long rslen, VALUE rs)
}
static VALUE
rb_io_getline(VALUE rs, VALUE io)
rb_io_getline(int argc, VALUE *argv, VALUE io)
{
VALUE str = Qnil;
VALUE rs, lim, str = Qnil;
OpenFile *fptr;
long limit;
if (argc == 0) {
rs = rb_rs;
lim = Qnil;
}
else {
rb_scan_args(argc, argv, "11", &rs, &lim);
if (NIL_P(lim) && !NIL_P(rs) && TYPE(rs) != T_STRING) {
VALUE tmp = rb_check_string_type(rs);
if (NIL_P(tmp)) {
lim = rs;
rs = rb_rs;
}
else {
rs = tmp;
}
}
}
limit = NIL_P(lim) ? 0 : NUM2LONG(lim);
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
@ -1660,8 +1695,11 @@ rb_io_getline(VALUE rs, VALUE io)
str = read_all(fptr, 0, Qnil);
if (RSTRING_LEN(str) == 0) return Qnil;
}
else if (!NIL_P(lim) && limit == 0) {
return rb_str_new(0,0);
}
else if (rs == rb_default_rs) {
return rb_io_getline_fast(fptr, '\n');
return rb_io_getline_fast(fptr, '\n', limit);
}
else {
int c, newline;
@ -1677,20 +1715,21 @@ rb_io_getline(VALUE rs, VALUE io)
swallow(fptr, '\n');
}
else if (rslen == 1) {
return rb_io_getline_fast(fptr, (unsigned char)RSTRING_PTR(rs)[0]);
return rb_io_getline_fast(fptr, (unsigned char)RSTRING_PTR(rs)[0], limit);
}
else {
rsptr = RSTRING_PTR(rs);
}
newline = rsptr[rslen - 1];
while ((c = appendline(fptr, newline, &str)) != EOF) {
while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
if (c == newline) {
if (RSTRING_LEN(str) < rslen) continue;
if (!rspara) rscheck(rsptr, rslen, rs);
if (memcmp(RSTRING_PTR(str) + RSTRING_LEN(str) - rslen,
rsptr, rslen) == 0) break;
}
if (limit == 0) break;
}
if (rspara) {
@ -1701,8 +1740,10 @@ rb_io_getline(VALUE rs, VALUE io)
}
if (!NIL_P(str)) {
if (limit > 0) {
fptr->lineno++;
lineno = INT2FIX(fptr->lineno);
}
OBJ_TAINT(str);
}
@ -1716,21 +1757,25 @@ rb_io_gets(VALUE io)
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
return rb_io_getline_fast(fptr, '\n');
return rb_io_getline_fast(fptr, '\n', 0);
}
/*
* call-seq:
* ios.gets(sep_string=$/) => string or nil
* ios.gets(sep=$/) => string or nil
* ios.gets(limit) => string or nil
* ios.gets(sep, limit) => string or nil
*
* Reads the next ``line'' from the I/O stream; lines are separated by
* <i>sep_string</i>. A separator of <code>nil</code> reads the entire
* <i>sep</i>. A separator of <code>nil</code> reads the entire
* contents, and a zero-length separator reads the input a paragraph at
* a time (two successive newlines in the input separate paragraphs).
* The stream must be opened for reading or an <code>IOError</code>
* will be raised. The line read in will be returned and also assigned
* to <code>$_</code>. Returns <code>nil</code> if called at end of
* file.
* file. If the first argument is an integer, or optional second
* argument is given, the returning string would not be longer than the
* given value.
*
* File.new("testfile").gets #=> "This is line one\n"
* $_ #=> "This is line one\n"
@ -1739,16 +1784,9 @@ rb_io_gets(VALUE io)
static VALUE
rb_io_gets_m(int argc, VALUE *argv, VALUE io)
{
VALUE rs, str;
VALUE str;
if (argc == 0) {
rs = rb_rs;
}
else {
rb_scan_args(argc, argv, "1", &rs);
if (!NIL_P(rs)) StringValue(rs);
}
str = rb_io_getline(rs, io);
str = rb_io_getline(argc, argv, io);
rb_lastline_set(str);
return str;
@ -1834,7 +1872,9 @@ argf_lineno(void)
/*
* call-seq:
* ios.readline(sep_string=$/) => string
* ios.readline(sep=$/) => string
* ios.readline(limit) => string
* ios.readline(sep, limit) => string
*
* Reads a line as with <code>IO#gets</code>, but raises an
* <code>EOFError</code> on end of file.
@ -1853,14 +1893,17 @@ rb_io_readline(int argc, VALUE *argv, VALUE io)
/*
* call-seq:
* ios.readlines(sep_string=$/) => array
* ios.readlines(sep=$/) => array
* ios.readlines(limit) => array
* ios.readlines(sep, limit) => array
*
* Reads all of the lines in <em>ios</em>, and returns them in
* <i>anArray</i>. Lines are separated by the optional
* <i>sep_string</i>. If <i>sep_string</i> is <code>nil</code>, the
* rest of the stream is returned as a single record.
* The stream must be opened for reading or an
* <code>IOError</code> will be raised.
* <i>anArray</i>. Lines are separated by the optional <i>sep</i>. If
* <i>sep</i> is <code>nil</code>, the rest of the stream is returned
* as a single record. If the first argument is an integer, or
* optional second argument is given, the returning string would not be
* longer than the given value. The stream must be opened for reading
* or an <code>IOError</code> will be raised.
*
* f = File.new("testfile")
* f.readlines[0] #=> "This is line one\n"
@ -1870,17 +1913,9 @@ static VALUE
rb_io_readlines(int argc, VALUE *argv, VALUE io)
{
VALUE line, ary;
VALUE rs;
if (argc == 0) {
rs = rb_rs;
}
else {
rb_scan_args(argc, argv, "1", &rs);
if (!NIL_P(rs)) StringValue(rs);
}
ary = rb_ary_new();
while (!NIL_P(line = rb_io_getline(rs, io))) {
while (!NIL_P(line = rb_io_getline(argc, argv, io))) {
rb_ary_push(ary, line);
}
return ary;
@ -1888,11 +1923,15 @@ rb_io_readlines(int argc, VALUE *argv, VALUE io)
/*
* call-seq:
* ios.each(sep_string=$/) {|line| block } => ios
* ios.each_line(sep_string=$/) {|line| block } => ios
* ios.each(sep=$/) {|line| block } => ios
* ios.each(limit) {|line| block } => ios
* ios.each(sep,limit) {|line| block } => ios
* ios.each_line(sep=$/) {|line| block } => ios
* ios.each_line(limit) {|line| block } => ios
* ios.each_line(sep,limit) {|line| block } => ios
*
* Executes the block for every line in <em>ios</em>, where lines are
* separated by <i>sep_string</i>. <em>ios</em> must be opened for
* separated by <i>sep</i>. <em>ios</em> must be opened for
* reading or an <code>IOError</code> will be raised.
*
* f = File.new("testfile")
@ -1910,17 +1949,9 @@ static VALUE
rb_io_each_line(int argc, VALUE *argv, VALUE io)
{
VALUE str;
VALUE rs;
RETURN_ENUMERATOR(io, argc, argv);
if (argc == 0) {
rs = rb_rs;
}
else {
rb_scan_args(argc, argv, "1", &rs);
if (!NIL_P(rs)) StringValue(rs);
}
while (!NIL_P(str = rb_io_getline(rs, io))) {
while (!NIL_P(str = rb_io_getline(argc, argv, io))) {
rb_yield(str);
}
return io;
@ -1963,7 +1994,9 @@ rb_io_each_byte(VALUE io)
/*
* call-seq:
* str.lines(separator=$/) => anEnumerator
* str.lines(sep=$/) => anEnumerator
* str.lines(limit) => anEnumerator
* str.lines(sep, limit) => anEnumerator
*
* Returns an enumerator that gives each line in the string.
*
@ -4371,16 +4404,7 @@ argf_getline(int argc, VALUE *argv)
line = rb_io_gets(current_file);
}
else {
VALUE rs;
if (argc == 0) {
rs = rb_rs;
}
else {
rb_scan_args(argc, argv, "1", &rs);
if (!NIL_P(rs)) StringValue(rs);
}
line = rb_io_getline(rs, current_file);
line = rb_io_getline(argc, argv, current_file);
}
if (NIL_P(line) && next_p != -1) {
argf_close(current_file);
@ -4396,18 +4420,22 @@ argf_getline(int argc, VALUE *argv)
/*
* call-seq:
* gets(separator=$/) => string or nil
* gets(sep=$/) => string or nil
* gets(limit) => string or nil
* gets(sep,limit) => string or nil
*
* Returns (and assigns to <code>$_</code>) the next line from the list
* of files in +ARGV+ (or <code>$*</code>), or from standard
* input if no files are present on the command line. Returns
* +nil+ at end of file. The optional argument specifies the
* record separator. The separator is included with the contents of
* each record. A separator of +nil+ reads the entire
* contents, and a zero-length separator reads the input one paragraph
* at a time, where paragraphs are divided by two consecutive newlines.
* If multiple filenames are present in +ARGV+,
* +gets(nil)+ will read the contents one file at a time.
* of files in +ARGV+ (or <code>$*</code>), or from standard input if
* no files are present on the command line. Returns +nil+ at end of
* file. The optional argument specifies the record separator. The
* separator is included with the contents of each record. A separator
* of +nil+ reads the entire contents, and a zero-length separator
* reads the input one paragraph at a time, where paragraphs are
* divided by two consecutive newlines. If the first argument is an
* integer, or optional second argument is given, the returning string
* would not be longer than the given value. If multiple filenames are
* present in +ARGV+, +gets(nil)+ will read the contents one file at a
* time.
*
* ARGV << "testfile"
* print while gets
@ -4467,7 +4495,9 @@ rb_gets(void)
/*
* call-seq:
* readline(separator=$/) => string
* readline(sep=$/) => string
* readline(limit) => string
* readline(sep, limit) => string
*
* Equivalent to <code>Kernel::gets</code>, except
* +readline+ raises +EOFError+ at end of file.
@ -4503,10 +4533,12 @@ rb_f_getc(void)
/*
* call-seq:
* readlines(separator=$/) => array
* readlines(sep=$/) => array
* readlines(limit) => array
* readlines(sep,limit) => array
*
* Returns an array containing the lines returned by calling
* <code>Kernel.gets(<i>separator</i>)</code> until the end of file.
* <code>Kernel.gets(<i>sep</i>)</code> until the end of file.
*/
static VALUE
@ -5079,7 +5111,7 @@ rb_io_s_pipe(VALUE klass)
struct foreach_arg {
int argc;
VALUE sep;
VALUE *argv;
VALUE io;
};
@ -5088,7 +5120,7 @@ io_s_foreach(struct foreach_arg *arg)
{
VALUE str;
while (!NIL_P(str = rb_io_getline(arg->sep, arg->io))) {
while (!NIL_P(str = rb_io_gets_m(arg->argc, arg->argv, arg->io))) {
rb_yield(str);
}
return Qnil;
@ -5096,10 +5128,12 @@ io_s_foreach(struct foreach_arg *arg)
/*
* call-seq:
* IO.foreach(name, sep_string=$/) {|line| block } => nil
* IO.foreach(name, sep=$/) {|line| block } => nil
* IO.foreach(name, limit) {|line| block } => nil
* IO.foreach(name, sep, limit) {|line| block } => nil
*
* Executes the block for every line in the named I/O port, where lines
* are separated by <em>sep_string</em>.
* are separated by <em>sep</em>.
*
* IO.foreach("testfile") {|x| print "GOT ", x }
*
@ -5118,33 +5152,30 @@ rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
struct foreach_arg arg;
RETURN_ENUMERATOR(self, argc, argv);
rb_scan_args(argc, argv, "11", &fname, &arg.sep);
rb_scan_args(argc, argv, "12", &fname, NULL, NULL);
FilePathValue(fname);
if (argc == 1) {
arg.sep = rb_default_rs;
}
else if (!NIL_P(arg.sep)) {
StringValue(arg.sep);
}
arg.io = rb_io_open(RSTRING_PTR(fname), "r");
if (NIL_P(arg.io)) return Qnil;
arg.argc = argc - 1;
arg.argv = argv + 1;
return rb_ensure(io_s_foreach, (VALUE)&arg, rb_io_close, arg.io);
}
static VALUE
io_s_readlines(struct foreach_arg *arg)
{
return rb_io_readlines(arg->argc, &arg->sep, arg->io);
return rb_io_readlines(arg->argc, arg->argv, arg->io);
}
/*
* call-seq:
* IO.readlines(name, sep_string=$/) => array
* IO.readlines(name, sep=$/) => array
* IO.readlines(name, limit) => array
* IO.readlines(name, sep, limit) => array
*
* Reads the entire file specified by <i>name</i> as individual
* lines, and returns those lines in an array. Lines are separated by
* <i>sep_string</i>.
* <i>sep</i>.
*
* a = IO.readlines("testfile")
* a[0] #=> "This is line one\n"
@ -5157,18 +5188,19 @@ rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
VALUE fname;
struct foreach_arg arg;
rb_scan_args(argc, argv, "11", &fname, &arg.sep);
rb_scan_args(argc, argv, "12", &fname, NULL, NULL);
FilePathValue(fname);
arg.argc = argc - 1;
arg.io = rb_io_open(RSTRING_PTR(fname), "r");
if (NIL_P(arg.io)) return Qnil;
arg.argc = argc - 1;
arg.argv = argv + 1;
return rb_ensure(io_s_readlines, (VALUE)&arg, rb_io_close, arg.io);
}
static VALUE
io_s_read(struct foreach_arg *arg)
{
return io_read(arg->argc, &arg->sep, arg->io);
return io_read(arg->argc, arg->argv, arg->io);
}
/*
@ -5190,9 +5222,10 @@ rb_io_s_read(int argc, VALUE *argv, VALUE io)
VALUE fname, offset;
struct foreach_arg arg;
rb_scan_args(argc, argv, "12", &fname, &arg.sep, &offset);
rb_scan_args(argc, argv, "12", &fname, NULL, &offset);
FilePathValue(fname);
arg.argc = argc ? 1 : 0;
arg.argc = argc > 1 ? 1 : 0;
arg.argv = argv + 1;
arg.io = rb_io_open(RSTRING_PTR(fname), "r");
if (NIL_P(arg.io)) return Qnil;
if (!NIL_P(offset)) {
@ -5278,7 +5311,7 @@ argf_read(int argc, VALUE *argv)
VALUE tmp, str, length;
long len = 0;
rb_scan_args(argc, argv, "02", &length, &str);
rb_scan_args(argc, argv, "11", &length, &str);
if (!NIL_P(length)) {
len = NUM2LONG(argv[0]);
}

View file

@ -1,7 +1,7 @@
#define RUBY_VERSION "1.9.0"
#define RUBY_RELEASE_DATE "2006-12-28"
#define RUBY_RELEASE_DATE "2006-12-30"
#define RUBY_VERSION_CODE 190
#define RUBY_RELEASE_CODE 20061228
#define RUBY_RELEASE_CODE 20061230
#define RUBY_PATCHLEVEL 0
#define RUBY_VERSION_MAJOR 1
@ -9,7 +9,7 @@
#define RUBY_VERSION_TEENY 0
#define RUBY_RELEASE_YEAR 2006
#define RUBY_RELEASE_MONTH 12
#define RUBY_RELEASE_DAY 28
#define RUBY_RELEASE_DAY 30
RUBY_EXTERN const char ruby_version[];
RUBY_EXTERN const char ruby_release_date[];