diff --git a/src/streams.c b/src/streams.c index e6e5940ca3..5b76b5762c 100644 --- a/src/streams.c +++ b/src/streams.c @@ -1581,8 +1581,6 @@ Obj FuncPOSITION_FILE ( Obj self, Obj fid ) { - Int ret; - /* check the argument */ while ( ! IS_INTOBJ(fid) ) { fid = ErrorReturnObj( @@ -1590,9 +1588,22 @@ Obj FuncPOSITION_FILE ( (Int)TNAM_OBJ(fid), 0L, "you can replace via 'return ;'" ); } - - ret = SyFtell( INT_INTOBJ(fid) ); - return ret == -1 ? Fail : INTOBJ_INT(ret); + + Int ifid = INT_INTOBJ(fid); + Int ret = SyFtell(ifid); + + // Return if failed + if (ret == -1) { + return Fail; + } + + // Need to account for characters in buffer + if (syBuf[ifid].bufno >= 0) { + UInt bufno = syBuf[ifid].bufno; + ret -= syBuffers[bufno].buflen - syBuffers[bufno].bufstart; + } + + return INTOBJ_INT(ret); } diff --git a/tst/teststandard/files/empty.txt b/tst/teststandard/files/empty.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tst/teststandard/files/example.txt b/tst/teststandard/files/example.txt new file mode 100644 index 0000000000..5d9a637166 --- /dev/null +++ b/tst/teststandard/files/example.txt @@ -0,0 +1,3 @@ +here is line 1 + +here is line 2 diff --git a/tst/teststandard/files/examplegz.txt.gz b/tst/teststandard/files/examplegz.txt.gz new file mode 100644 index 0000000000..2b7630f300 Binary files /dev/null and b/tst/teststandard/files/examplegz.txt.gz differ diff --git a/tst/teststandard/files/files.tst b/tst/teststandard/files/files.tst new file mode 100644 index 0000000000..bcbd5de707 --- /dev/null +++ b/tst/teststandard/files/files.tst @@ -0,0 +1,111 @@ +gap> START_TEST("files.tst"); + +# Perform some general tests for reading from streams +# testName : A nice name to print out on failure +# openFunc : A zero-argument function which returns an InputStream +# lines : A list of the lines which should be in the file +# supportsPosition : Does the InputStream support +# PositionStream/SeekPositionStream/RewindStream? +gap> testRead := function(testName, openFunc, lines, supportsPosition) +> local file, i, j, read, line, byte, concatlines; +> # Check we can read many times, to check we close properly +> for i in [1..100] do +> file := openFunc(); +> for j in [1..Length(lines)] do +> line := ReadAllLine(file); +> if lines[j] <> line then +> PrintFormatted("Expected {!v}, found {!v}, at line {} in {}\n", +> lines[j], line, j, testName); +> fi; +> # it is valid to get, or not get, end of stream at end of last line +> if IsEndOfStream(file) and j < Length(lines) then +> Print("Unexpected end of stream in ", testName); +> fi; +> if supportsPosition then +> if PositionStream(file) <> Sum(lines{[1..j]},Length) then +> PrintFormatted("At position {}, expected {}, on line {} of {}\n", +> PositionStream(file), Sum(lines{[1..j]},Length), j, testName); +> fi; +> else +> if PositionStream(file) <> fail then +> Print("Unexpected PositionStream success ", testName, "\n"); +> fi; +> fi; +> od; +> if ReadAllLine(file) <> fail then +> Print("reading past end of file did not return 'fail' in ",testName, "\n"); +> fi; +> if not IsEndOfStream(file) then +> Print("failed to find end of stream in ", testName, "\n"); +> fi; +> if supportsPosition then +> if Length(lines) > 2 then +> SeekPositionStream(file, Length(lines[1])); +> if PositionStream(file) <> Length(lines[1]) then +> Print("failed seek position ", testName, "\n"); +> fi; +> if ReadAllLine(file) <> lines[2] then +> Print("failed read after seek ", testName, "\n"); +> fi; +> fi; +> if not SeekPositionStream(file, 0) or PositionStream(file) <> 0 then +> Print("failed seek to 0 ", testName, "\n"); +> fi; +> if not SeekPositionStream(file, Sum(lines, Length)) or +> PositionStream(file) <> Sum(lines, Length) then +> Print("failed seek to end ", testName, "\n"); +> fi; +> if ReadAllLine(file) <> fail then +> Print("failed read past end of file ", testName, "\n"); +> fi; +> if not RewindStream(file) or PositionStream(file) <> 0 then +> Print("failed rewind stream ", testName, "\n"); +> fi; +> else +> if SeekPositionStream(file, 0) <> fail then +> Print("Unexpected SeekPositionStream success ", testName, "\n"); +> fi; +> if RewindStream(file) <> fail then +> Print("Unexpected RewindStream success ", testName, "\n"); +> fi; +> fi; +> CloseStream(file); +> file := openFunc(); +> concatlines := Concatenation(lines); +> for i in [1..Length(concatlines)] do +> byte := ReadByte(file); +> if byte <> IntChar(concatlines[i]) then +> PrintFormatted("Expected {}, found {}, at position {} in {}\n", +> IntChar(concatlines[i]), byte, i, testName); +> fi; +> if i <> Length(concatlines) and IsEndOfStream(file) then +> PrintFormatted("Unexpected end of stream in {}\n", testName); +> fi; +> if supportsPosition and PositionStream(file) <> i then +> PrintFormatted("Expected to be at {}, instead at {}, in {}\n", +> i, PositionStream(i), testName); +> fi; +> od; +> if ReadByte(file) <> fail then +> PrintFormatted("Unexpected extra byte in {}\n", testName); +> fi; +> if not IsEndOfStream(file) then +> PrintFormatted("Exepected end of stream in {}\n", testName); +> fi; +> CloseStream(file); +> od; +> end;; +gap> dir := DirectoriesLibrary("tst/teststandard/files");; +gap> lines := ["here is line 1\n", "\n", "here is line 2\n"];; +gap> testRead("example.txt", {} -> InputTextFile(Filename(dir, "example.txt")), +> lines, true); + +# Test automatic gzip detection +gap> testRead("example.txt", {} -> InputTextFile(Filename(dir, "examplegz.txt")), +> lines, false); +gap> testRead("empty.txt", {} -> InputTextFile(Filename(dir, "empty.txt")), +> [], true); +gap> testRead("lines string", {} -> InputTextString(Concatenation(lines)), lines, true); +gap> testRead("empty string", {} -> InputTextString(""), [], true); +gap> testRead("dummy input", {} -> InputTextNone(), [], true); +gap> STOP_TEST("files.tst", 1);