-- vim: ft=terra
-- TODO: add support for windows IO calls
local handle_type = int
local posix = terralib.includec 'fcntl.h'
local unistd = terralib.includec 'unistd.h'
local mm = terralib.includec 'sys/mman.h'
struct file {
handle: handle_type
read: bool
write: bool
}
file.mode = { read = 0, write = 1, rw = 2 }
file.seek = { abs = 0, ofs = 1, eof = 2 }
file.methods = {
open = terra(path: rawstring, mode: uint8)
var f: file
var flag: int
if mode == [file.mode.rw] then
flag = posix.O_RDWR
f.read = true f.write = true
elseif mode == [file.mode.read] then
flag = posix.O_RDONLY
f.read = true f.write = false
elseif mode == [file.mode.read] then
flag = posix.O_WRONLY
f.read = false f.write = true
else lib.bail('invalid file mode') end
lib.dbg('opening file ', path)
f.handle = posix.open(path, flag)
var r: lib.stat(file)
if f.handle == -1 then
r.ok = false
r.error = 1 -- TODO get errno somehow?
else
r.ok = true
r.val = f
end
return r
end;
close = terra(self: &file)
unistd.close(self.handle)
self.handle = -1
self.read = false
self.write = false
end;
read = terra(self: &file, dest: rawstring, sz: intptr): ptrdiff
return unistd.read(self.handle,dest,sz)
end;
write = terra(self: &file, data: &opaque, sz: intptr): ptrdiff
return unistd.write(self.handle,data,sz)
end;
seek = terra(self: &file, ofs: ptrdiff, wh: int)
var whence: int
if wh == [file.seek.abs] then
whence = unistd.SEEK_SET
elseif wh == [file.seek.ofs] then
whence = unistd.SEEK_CUR
elseif wh == [file.seek.eof] then
whence = unistd.SEEK_END
else lib.bail('invalid seek mode') end
return unistd.lseek(self.handle, ofs, whence)
end;
}
terra file:len(): intptr
var cur = self:seek(0, [file.seek.ofs])
var sz = self:seek(0, [file.seek.eof])
self:seek(cur, [file.seek.abs])
return sz
end
local struct mapping {
addr: &opaque
sz: intptr
}
terra mapping:unmap()
lib.dbg('releasing file mapping')
return mm.munmap(self.addr, self.sz)
end
-- provide for syncing mechanism?
terra file:mapin(ofs: intptr, sz: intptr)
var prot = 0
if self.read then prot = mm.PROT_READ end
if self.write then prot = prot or mm.PROT_WRITE end
if sz == 0 then sz = self:len() end
lib.dbg('mapping file into memory')
return mapping {
addr = mm.mmap(nil, sz, prot, mm.MAP_PRIVATE, self.handle, ofs);
sz = sz;
}
end
return file