Merge branch 'master' of git://factorcode.org/git/factor

db4
Joe Groff 2009-10-03 21:02:21 -05:00
commit 26ddc44dc0
22 changed files with 300 additions and 37 deletions

View File

@ -49,6 +49,9 @@ M: fd cancel-operation ( fd -- )
2bi 2bi
] if ; ] if ;
M: unix tell-handle ( handle -- n )
fd>> 0 SEEK_CUR lseek [ io-error ] [ ] bi ;
M: unix seek-handle ( n seek-type handle -- ) M: unix seek-handle ( n seek-type handle -- )
swap { swap {
{ io:seek-absolute [ SEEK_SET ] } { io:seek-absolute [ SEEK_SET ] }

View File

@ -124,8 +124,14 @@ M: output-port stream-write
HOOK: (wait-to-write) io-backend ( port -- ) HOOK: (wait-to-write) io-backend ( port -- )
HOOK: tell-handle os ( handle -- n )
HOOK: seek-handle os ( n seek-type handle -- ) HOOK: seek-handle os ( n seek-type handle -- )
M: buffered-port stream-tell ( stream -- n )
[ check-disposed ]
[ handle>> tell-handle ]
[ [ buffer>> size>> - 0 max ] [ buffer>> pos>> ] bi + ] tri ;
M: input-port stream-seek ( n seek-type stream -- ) M: input-port stream-seek ( n seek-type stream -- )
[ check-disposed ] [ check-disposed ]
[ buffer>> 0 swap buffer-reset ] [ buffer>> 0 swap buffer-reset ]

View File

@ -44,4 +44,3 @@ M: duplex-stream underlying-handle
>duplex-stream< >duplex-stream<
[ underlying-handle ] bi@ [ underlying-handle ] bi@
[ = [ invalid-duplex-stream ] when ] keep ; [ = [ invalid-duplex-stream ] when ] keep ;

View File

@ -24,7 +24,22 @@ HELP: limit
" \"123456\" <string-reader> 3 stream-throws limit" " \"123456\" <string-reader> 3 stream-throws limit"
" 100 swap stream-read ." " 100 swap stream-read ."
"] [ ] recover ." "] [ ] recover ."
"T{ limit-exceeded }" """T{ limit-exceeded
{ n 1 }
{ stream
T{ limited-stream
{ stream
T{ string-reader
{ underlying "123456" }
{ i 3 }
}
}
{ mode stream-throws }
{ count 4 }
{ limit 3 }
}
}
}"""
} }
"Returning " { $link f } " on exhaustion:" "Returning " { $link f } " on exhaustion:"
{ $example { $example

View File

@ -1,7 +1,8 @@
USING: io io.streams.limited io.encodings io.encodings.string USING: accessors continuations destructors io io.encodings
io.encodings.ascii io.encodings.binary io.streams.byte-array io.encodings.8-bit io.encodings.ascii io.encodings.binary
namespaces tools.test strings kernel io.streams.string accessors io.encodings.string io.encodings.utf8 io.files io.pipes
io.encodings.utf8 io.files destructors ; io.streams.byte-array io.streams.limited io.streams.string
kernel namespaces strings tools.test system ;
IN: io.streams.limited.tests IN: io.streams.limited.tests
[ ] [ [ ] [
@ -89,3 +90,127 @@ IN: io.streams.limited.tests
unlimited-input contents unlimited-input contents
] with-input-stream ] with-input-stream
] unit-test ] unit-test
[ 4 ] [
"abcdefgh" <string-reader> 4 stream-throws <limited-stream> [
4 seek-relative seek-input tell-input
] with-input-stream
] unit-test
[
"abcdefgh" <string-reader> 4 stream-throws <limited-stream> [
4 seek-relative seek-input
4 read
] with-input-stream
] [
limit-exceeded?
] must-fail-with
[
"abcdefgh" <string-reader> 4 stream-throws <limited-stream> [
4 seek-relative seek-input
-2 seek-relative
2 read
] with-input-stream
] [
limit-exceeded?
] must-fail-with
[
"abcdefgh" <string-reader> [
4 seek-relative seek-input
2 stream-throws limit-input
-2 seek-relative seek-input
2 read
] with-input-stream
] [
limit-exceeded?
] must-fail-with
[ "ef" ] [
"abcdefgh" <string-reader> [
4 seek-relative seek-input
2 stream-throws limit-input
4 seek-absolute seek-input
2 read
] with-input-stream
] unit-test
[ "ef" ] [
"abcdefgh" <string-reader> [
4 seek-absolute seek-input
2 stream-throws limit-input
2 seek-absolute seek-input
4 seek-absolute seek-input
2 read
] with-input-stream
] unit-test
! stream-throws, pipes are duplex and not seekable
[ "as" ] [
latin1 <pipe> [ 2 stream-throws <limited-stream> ] change-in
"asdf" over stream-write dup stream-flush
2 swap stream-read
] unit-test
[
latin1 <pipe> [ 2 stream-throws <limited-stream> ] change-in
"asdf" over stream-write dup stream-flush
3 swap stream-read
] [
limit-exceeded?
] must-fail-with
! stream-eofs, pipes are duplex and not seekable
[ "as" ] [
latin1 <pipe> [ 2 stream-eofs <limited-stream> ] change-in
"asdf" over stream-write dup stream-flush
2 swap stream-read
] unit-test
[ "as" ] [
latin1 <pipe> [ 2 stream-eofs <limited-stream> ] change-in
"asdf" over stream-write dup stream-flush
3 swap stream-read
] unit-test
! test seeking on limited unseekable streams
[ "as" ] [
latin1 <pipe> [ 2 stream-eofs <limited-stream> ] change-in
"asdf" over stream-write dup stream-flush
2 swap stream-read
] unit-test
[ "as" ] [
latin1 <pipe> [ 2 stream-eofs <limited-stream> ] change-in
"asdf" over stream-write dup stream-flush
3 swap stream-read
] unit-test
[
latin1 <pipe> [ 2 stream-throws <limited-stream> ] change-in
2 seek-absolute rot in>> stream-seek
] must-fail
[
"as"
] [
latin1 <pipe> [ 2 stream-throws <limited-stream> ] change-in
"asdf" over stream-write dup stream-flush
[ 2 seek-absolute rot in>> stream-seek ] [ drop ] recover
2 swap stream-read
] unit-test
[ 7 ] [
image binary stream-throws <limited-file-reader> [
7 read drop
tell-input
] with-input-stream
] unit-test
[ 70000 ] [
image binary stream-throws <limited-file-reader> [
70000 read drop
tell-input
] with-input-stream
] unit-test

View File

@ -2,11 +2,14 @@
! Copyright (C) 2009 Doug Coleman. ! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors byte-vectors combinators destructors fry io USING: accessors byte-vectors combinators destructors fry io
io.encodings io.files io.files.info kernel math namespaces io.encodings io.files io.files.info kernel locals math
sequences ; namespaces sequences ;
IN: io.streams.limited IN: io.streams.limited
TUPLE: limited-stream stream count limit mode stack ; TUPLE: limited-stream
stream mode
count limit
current start stop ;
SINGLETONS: stream-throws stream-eofs ; SINGLETONS: stream-throws stream-eofs ;
@ -51,13 +54,27 @@ M: object unlimited ( stream -- stream' )
: with-limited-stream ( stream limit mode quot -- ) : with-limited-stream ( stream limit mode quot -- )
[ limit ] dip call ; inline [ limit ] dip call ; inline
ERROR: limit-exceeded ; ERROR: limit-exceeded n stream ;
ERROR: bad-stream-mode mode ; ERROR: bad-stream-mode mode ;
<PRIVATE <PRIVATE
: adjust-limit ( n stream -- n' stream ) : adjust-current-limit ( n stream -- n' stream )
2dup [ + ] change-current
[ current>> ] [ stop>> ] bi >
[
dup mode>> {
{ stream-throws [ limit-exceeded ] }
{ stream-eofs [
dup [ current>> ] [ stop>> ] bi -
'[ _ - ] dip
] }
[ bad-stream-mode ]
} case
] when ; inline
: adjust-count-limit ( n stream -- n' stream )
2dup [ + ] change-count 2dup [ + ] change-count
[ count>> ] [ limit>> ] bi > [ count>> ] [ limit>> ] bi >
[ [
@ -66,13 +83,29 @@ ERROR: bad-stream-mode mode ;
{ stream-eofs [ { stream-eofs [
dup [ count>> ] [ limit>> ] bi - dup [ count>> ] [ limit>> ] bi -
'[ _ - ] dip '[ _ - ] dip
dup limit>> >>count
] } ] }
[ bad-stream-mode ] [ bad-stream-mode ]
} case } case
] when ; inline ] when ; inline
: check-count-bounds ( n stream -- n stream )
dup [ count>> ] [ limit>> ] bi >
[ limit-exceeded ] when ;
: check-current-bounds ( n stream -- n stream )
dup [ current>> ] [ start>> ] bi <
[ limit-exceeded ] when ;
: adjust-limited-read ( n stream -- n stream )
dup start>> [
check-current-bounds adjust-current-limit
] [
check-count-bounds adjust-count-limit
] if ;
: maybe-read ( n limited-stream quot: ( n stream -- seq/f ) -- seq/f ) : maybe-read ( n limited-stream quot: ( n stream -- seq/f ) -- seq/f )
[ adjust-limit ] dip [ adjust-limited-read ] dip
pick 0 <= [ 3drop f ] [ [ stream>> ] dip call ] if ; inline pick 0 <= [ 3drop f ] [ [ stream>> ] dip call ] if ; inline
PRIVATE> PRIVATE>
@ -93,16 +126,35 @@ M: limited-stream stream-read-partial
3dup [ [ stream-read1 dup ] dip memq? ] dip 3dup [ [ stream-read1 dup ] dip memq? ] dip
swap [ drop ] [ push (read-until) ] if ; swap [ drop ] [ push (read-until) ] if ;
:: limited-stream-seek ( n seek-type stream -- )
seek-type {
{ seek-absolute [ n stream (>>current) ] }
{ seek-relative [ stream [ n + ] change-current drop ] }
{ seek-end [ stream stop>> n - stream (>>current) ] }
[ bad-seek-type ]
} case ;
: >limited-seek ( stream -- stream' )
dup start>> [
dup stream-tell >>current
dup [ current>> ] [ count>> ] bi - >>start
dup [ start>> ] [ limit>> ] bi + >>stop
] unless ;
PRIVATE> PRIVATE>
M: limited-stream stream-read-until M: limited-stream stream-read-until
swap BV{ } clone (read-until) [ 2nip B{ } like ] dip ; swap BV{ } clone (read-until) [ 2nip B{ } like ] dip ;
M: limited-stream stream-seek M: limited-stream stream-tell
stream>> stream-seek ; stream>> stream-tell ;
M: limited-stream dispose M: limited-stream stream-seek
stream>> dispose ; >limited-seek
[ stream>> stream-seek ]
[ limited-stream-seek ] 3bi ;
M: limited-stream dispose stream>> dispose ;
M: limited-stream stream-element-type M: limited-stream stream-element-type
stream>> stream-element-type ; stream>> stream-element-type ;

View File

@ -2,7 +2,8 @@
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors io kernel math namespaces sequences sbufs USING: accessors io kernel math namespaces sequences sbufs
strings generic splitting continuations destructors sequences.private strings generic splitting continuations destructors sequences.private
io.streams.plain io.encodings math.order growable io.streams.sequence ; io.streams.plain io.encodings math.order growable io.streams.sequence
io.private ;
IN: io.streams.string IN: io.streams.string
! Readers ! Readers
@ -13,6 +14,8 @@ M: string-reader stream-read-partial stream-read ;
M: string-reader stream-read sequence-read ; M: string-reader stream-read sequence-read ;
M: string-reader stream-read1 sequence-read1 ; M: string-reader stream-read1 sequence-read1 ;
M: string-reader stream-read-until sequence-read-until ; M: string-reader stream-read-until sequence-read-until ;
M: string-reader stream-tell i>> ;
M: string-reader stream-seek (stream-seek) ;
M: string-reader dispose drop ; M: string-reader dispose drop ;
<PRIVATE <PRIVATE

View File

@ -486,6 +486,7 @@ tuple
{ "fputc" "io.streams.c" (( ch alien -- )) } { "fputc" "io.streams.c" (( ch alien -- )) }
{ "fwrite" "io.streams.c" (( string alien -- )) } { "fwrite" "io.streams.c" (( string alien -- )) }
{ "fflush" "io.streams.c" (( alien -- )) } { "fflush" "io.streams.c" (( alien -- )) }
{ "ftell" "io.streams.c" (( alien -- n )) }
{ "fseek" "io.streams.c" (( alien offset whence -- )) } { "fseek" "io.streams.c" (( alien offset whence -- )) }
{ "fclose" "io.streams.c" (( alien -- )) } { "fclose" "io.streams.c" (( alien -- )) }
{ "<wrapper>" "kernel" (( obj -- wrapper )) } { "<wrapper>" "kernel" (( obj -- wrapper )) }

View File

@ -1,6 +1,6 @@
USING: io.files io.streams.string io io.streams.byte-array USING: io.files io.streams.string io io.streams.byte-array
tools.test kernel io.encodings.ascii io.encodings.utf8 tools.test kernel io.encodings.ascii io.encodings.utf8
namespaces accessors io.encodings ; namespaces accessors io.encodings io.streams.limited ;
IN: io.streams.encodings.tests IN: io.streams.encodings.tests
[ { } ] [ { } ]

View File

@ -50,6 +50,10 @@ M: object <decoder> f decoder boa ;
M: decoder stream-element-type M: decoder stream-element-type
drop +character+ ; drop +character+ ;
M: decoder stream-tell stream>> stream-tell ;
M: decoder stream-seek stream>> stream-seek ;
M: decoder stream-read1 M: decoder stream-read1
dup >decoder< decode-char fix-read1 ; dup >decoder< decode-char fix-read1 ;

View File

@ -86,6 +86,14 @@ HELP: stream-copy
{ $description "Copies the contents of one stream into another, closing both streams when done." } { $description "Copies the contents of one stream into another, closing both streams when done." }
$io-error ; $io-error ;
HELP: stream-tell
{ $values
{ "stream" "a stream" } { "n" integer }
}
{ $description "Returns the index of the stream pointer if the stream is seekable." }
{ $notes "Stream seeking is not supported on streams that do not have a known length, e.g. TCP/IP streams." } ;
HELP: stream-seek HELP: stream-seek
{ $values { $values
{ "n" integer } { "seek-type" "a seek singleton" } { "stream" "a stream" } { "n" integer } { "seek-type" "a seek singleton" } { "stream" "a stream" }
@ -274,8 +282,11 @@ $nl
} }
"This word is only required for string output streams:" "This word is only required for string output streams:"
{ $subsections stream-nl } { $subsections stream-nl }
"This word is for streams that allow seeking:" "These words are for seekable streams:"
{ $subsections stream-seek } { $subsections
stream-tell
stream-seek
}
{ $see-also "io.timeouts" } ; { $see-also "io.timeouts" } ;
ARTICLE: "stdio-motivation" "Motivation for default streams" ARTICLE: "stdio-motivation" "Motivation for default streams"

View File

@ -1,7 +1,7 @@
! Copyright (C) 2003, 2009 Slava Pestov. ! Copyright (C) 2003, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: hashtables generic kernel math namespaces make sequences USING: accessors combinators continuations destructors kernel
continuations destructors assocs combinators ; math namespaces sequences ;
IN: io IN: io
SYMBOLS: +byte+ +character+ ; SYMBOLS: +byte+ +character+ ;
@ -23,9 +23,24 @@ ERROR: bad-seek-type type ;
SINGLETONS: seek-absolute seek-relative seek-end ; SINGLETONS: seek-absolute seek-relative seek-end ;
GENERIC: stream-tell ( stream -- n )
GENERIC: stream-seek ( n seek-type stream -- ) GENERIC: stream-seek ( n seek-type stream -- )
: stream-print ( str stream -- ) [ stream-write ] keep stream-nl ; <PRIVATE
SLOT: i
: (stream-seek) ( n seek-type stream -- )
swap {
{ seek-absolute [ (>>i) ] }
{ seek-relative [ [ + ] change-i drop ] }
{ seek-end [ [ underlying>> length + ] [ (>>i) ] bi ] }
[ bad-seek-type ]
} case ;
PRIVATE>
: stream-print ( str stream -- ) [ stream-write ] [ stream-nl ] bi ;
! Default streams ! Default streams
SYMBOL: input-stream SYMBOL: input-stream
@ -37,6 +52,8 @@ SYMBOL: error-stream
: read ( n -- seq ) input-stream get stream-read ; : read ( n -- seq ) input-stream get stream-read ;
: read-until ( seps -- seq sep/f ) input-stream get stream-read-until ; : read-until ( seps -- seq sep/f ) input-stream get stream-read-until ;
: read-partial ( n -- seq ) input-stream get stream-read-partial ; : read-partial ( n -- seq ) input-stream get stream-read-partial ;
: tell-input ( -- n ) input-stream get stream-tell ;
: tell-output ( -- n ) output-stream get stream-tell ;
: seek-input ( n seek-type -- ) input-stream get stream-seek ; : seek-input ( n seek-type -- ) input-stream get stream-seek ;
: seek-output ( n seek-type -- ) output-stream get stream-seek ; : seek-output ( n seek-type -- ) output-stream get stream-seek ;

View File

@ -29,6 +29,10 @@ io.encodings.utf8 io kernel arrays strings namespaces math ;
] with-byte-reader ] with-byte-reader
] unit-test ] unit-test
[ 0 ] [
B{ 1 2 3 4 5 6 7 8 9 10 11 12 } binary [ tell-input ] with-byte-reader
] unit-test
! Overly aggressive compiler optimizations ! Overly aggressive compiler optimizations
[ B{ 123 } ] [ [ B{ 123 } ] [
binary [ 123 >bignum write1 ] with-byte-writer binary [ 123 >bignum write1 ] with-byte-writer

View File

@ -1,8 +1,8 @@
! Copyright (C) 2008, 2009 Daniel Ehrenberg ! Copyright (C) 2008, 2009 Daniel Ehrenberg
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: byte-arrays byte-vectors kernel io.encodings sequences io USING: accessors byte-arrays byte-vectors destructors io
namespaces io.encodings.private accessors sequences.private io.encodings io.private io.streams.sequence kernel namespaces
io.streams.sequence destructors math combinators ; sequences sequences.private ;
IN: io.streams.byte-array IN: io.streams.byte-array
M: byte-vector stream-element-type drop +byte+ ; M: byte-vector stream-element-type drop +byte+ ;
@ -24,13 +24,8 @@ M: byte-reader stream-read1 sequence-read1 ;
M: byte-reader stream-read-until sequence-read-until ; M: byte-reader stream-read-until sequence-read-until ;
M: byte-reader dispose drop ; M: byte-reader dispose drop ;
M: byte-reader stream-seek ( n seek-type stream -- ) M: byte-reader stream-tell i>> ;
swap { M: byte-reader stream-seek (stream-seek) ;
{ seek-absolute [ (>>i) ] }
{ seek-relative [ [ + ] change-i drop ] }
{ seek-end [ [ underlying>> length + ] keep (>>i) ] }
[ bad-seek-type ]
} case ;
: <byte-reader> ( byte-array encoding -- stream ) : <byte-reader> ( byte-array encoding -- stream )
[ B{ } like 0 byte-reader boa ] dip <decoder> ; [ B{ } like 0 byte-reader boa ] dip <decoder> ;

View File

@ -1,5 +1,5 @@
USING: tools.test io.files io.files.temp io io.streams.c USING: tools.test io.files io.files.temp io io.streams.c
io.encodings.ascii strings ; io.encodings.ascii strings destructors kernel ;
IN: io.streams.c.tests IN: io.streams.c.tests
[ "hello world" ] [ [ "hello world" ] [
@ -8,3 +8,12 @@ IN: io.streams.c.tests
"test.txt" temp-file "rb" fopen <c-reader> stream-contents "test.txt" temp-file "rb" fopen <c-reader> stream-contents
>string >string
] unit-test ] unit-test
[ 0 ]
[ "test.txt" temp-file "rb" fopen <c-reader> [ stream-tell ] [ dispose ] bi ] unit-test
[ 3 ] [
"test.txt" temp-file "rb" fopen <c-reader>
3 over stream-read drop
[ stream-tell ] [ dispose ] bi
] unit-test

View File

@ -13,6 +13,8 @@ TUPLE: c-stream < disposable handle ;
M: c-stream dispose* handle>> fclose ; M: c-stream dispose* handle>> fclose ;
M: c-stream stream-tell handle>> ftell ;
M: c-stream stream-seek M: c-stream stream-seek
handle>> swap { handle>> swap {
{ seek-absolute [ 0 ] } { seek-absolute [ 0 ] }

View File

@ -164,6 +164,17 @@ void factor_vm::primitive_fwrite()
} }
} }
void factor_vm::primitive_ftell()
{
FILE *file = (FILE *)unbox_alien();
off_t offset;
if((offset = FTELL(file)) == -1)
io_error();
box_signed_8(offset);
}
void factor_vm::primitive_fseek() void factor_vm::primitive_fseek()
{ {
int whence = to_fixnum(dpop()); int whence = to_fixnum(dpop());

View File

@ -23,6 +23,7 @@ typedef char symbol_char;
#define STRNCMP strncmp #define STRNCMP strncmp
#define STRDUP strdup #define STRDUP strdup
#define FTELL ftello
#define FSEEK fseeko #define FSEEK fseeko
#define FIXNUM_FORMAT "%ld" #define FIXNUM_FORMAT "%ld"

View File

@ -19,7 +19,8 @@ typedef wchar_t vm_char;
#define STRNCMP wcsncmp #define STRNCMP wcsncmp
#define STRDUP _wcsdup #define STRDUP _wcsdup
#define MIN(a,b) ((a)>(b)?(b):(a)) #define MIN(a,b) ((a)>(b)?(b):(a))
#define FSEEK fseek #define FTELL _ftelli64
#define FSEEK _fseeki64
#ifdef WIN64 #ifdef WIN64
#define CELL_FORMAT "%Iu" #define CELL_FORMAT "%Iu"

View File

@ -128,6 +128,7 @@ const primitive_type primitives[] = {
primitive_fputc, primitive_fputc,
primitive_fwrite, primitive_fwrite,
primitive_fflush, primitive_fflush,
primitive_ftell,
primitive_fseek, primitive_fseek,
primitive_fclose, primitive_fclose,
primitive_wrapper, primitive_wrapper,
@ -254,6 +255,7 @@ PRIMITIVE_FORWARD(fread)
PRIMITIVE_FORWARD(fputc) PRIMITIVE_FORWARD(fputc)
PRIMITIVE_FORWARD(fwrite) PRIMITIVE_FORWARD(fwrite)
PRIMITIVE_FORWARD(fflush) PRIMITIVE_FORWARD(fflush)
PRIMITIVE_FORWARD(ftell)
PRIMITIVE_FORWARD(fseek) PRIMITIVE_FORWARD(fseek)
PRIMITIVE_FORWARD(fclose) PRIMITIVE_FORWARD(fclose)
PRIMITIVE_FORWARD(wrapper) PRIMITIVE_FORWARD(wrapper)

View File

@ -136,6 +136,7 @@ PRIMITIVE(fread);
PRIMITIVE(fputc); PRIMITIVE(fputc);
PRIMITIVE(fwrite); PRIMITIVE(fwrite);
PRIMITIVE(fflush); PRIMITIVE(fflush);
PRIMITIVE(ftell);
PRIMITIVE(fseek); PRIMITIVE(fseek);
PRIMITIVE(fclose); PRIMITIVE(fclose);
PRIMITIVE(wrapper); PRIMITIVE(wrapper);

View File

@ -493,6 +493,7 @@ struct factor_vm
void primitive_fread(); void primitive_fread();
void primitive_fputc(); void primitive_fputc();
void primitive_fwrite(); void primitive_fwrite();
void primitive_ftell();
void primitive_fseek(); void primitive_fseek();
void primitive_fflush(); void primitive_fflush();
void primitive_fclose(); void primitive_fclose();