Skip to content

Commit

Permalink
Fixed seek and tell for large files
Browse files Browse the repository at this point in the history
  • Loading branch information
andralex committed Aug 16, 2010
1 parent caa561b commit 3eb9454
Showing 1 changed file with 54 additions and 11 deletions.
65 changes: 54 additions & 11 deletions std/stdio.d
Expand Up @@ -82,6 +82,7 @@ version (DIGITAL_MARS_STDIO)
alias setmode _setmode;
enum _O_BINARY = 0x8000;
int _fileno(FILE* f) { return f._file; }
alias _fileno fileno;
}
else version (GCC_IO)
{
Expand Down Expand Up @@ -518,26 +519,50 @@ If the file is not opened, throws an exception. Otherwise, calls $(WEB
cplusplus.com/reference/clibrary/cstdio/fseek.html, fseek) for the
file handle. Throws on error.
*/
void seek(long offset, int origin = SEEK_SET)
void seek(ulong offset, int origin = SEEK_SET)
{
enforce(p && p.handle,
"Attempting to seek() in an unopened file");
// @@@ Dubious: why is fseek in std.c.stdio taking an int???
errnoEnforce(core.stdc.stdio.fseek(
p.handle, to!int(offset), origin) == 0,
"Could not seek in file `"~p.name~"'");
if (offset <= int.max && origin == SEEK_SET)
{
errnoEnforce(core.stdc.stdio.fseek(
p.handle, cast(int) offset, origin) == 0,
"Could not seek in file `"~p.name~"'");
}
else
{
flush();
errnoEnforce(lseek64(fileno(), offset, origin) != ulong.max,
text("Could not seek to offset ", offset,
" in file `"~p.name~"'"));
}
}

unittest
{
auto f = File("deleteme", "w+");
scope(exit) { f.close(); std.file.remove("deleteme"); }
f.rawWrite("abcdefghijklmnopqrstuvwxyz");
f.seek(7);
assert(f.readln() == "hijklmnopqrstuvwxyz");
auto bigOffset = cast(ulong) int.max + 100;
f.seek(bigOffset);
assert(f.tell == bigOffset, text(f.tell));
// Uncomment the tests below only if you want to wait for a long time
// f.rawWrite("abcdefghijklmnopqrstuvwxyz");
// f.seek(-3, SEEK_END);
// assert(f.readln() == "xyz");
}

/**
If the file is not opened, throws an exception. Otherwise, calls $(WEB
cplusplus.com/reference/clibrary/cstdio/ftell.html, ftell) for the
managed file handle. Throws on error.
*/
ulong tell() const
@property ulong tell() const
{
enforce(p && p.handle,
"Attempting to tell() in an unopened file");
immutable result = .ftell(cast(FILE*) p.handle);
enforce(isOpen, "Attempting to tell() in an unopened file");
immutable result = lseek64(fileno(), 0, SEEK_CUR);
errnoEnforce(result != -1,
"Query ftell() failed for file `"~p.name~"'");
return result;
Expand Down Expand Up @@ -817,11 +842,11 @@ Returns the $(D FILE*) corresponding to this object.
/**
Returns the file number corresponding to this object.
*/
version(Posix) int fileno() const
/*version(Posix) */int fileno() const
{
enforce(p && p.handle,
"Attempting to call fileno() on an unopened file");
return core.stdc.stdio.fileno(cast(FILE*) p.handle);
return .fileno(cast(FILE*) p.handle);
}

/**
Expand Down Expand Up @@ -2378,3 +2403,21 @@ version(linux) {
return f;
}
}

version (Windows)
{
extern(C) ulong _lseeki64(int fd, ulong offset, int whence);
alias _lseeki64 lseek64;
}
else
{
import core.sys.posix.unistd : off_t, lseek;
static if (off_t.sizeof == 4)
{
extern(C) ulong lseek64(int fd, ulong offset, int whence);
}
else
{
alias lseek lseek64;
}
}

0 comments on commit 3eb9454

Please sign in to comment.