88 lines
2.6 KiB
Lua
88 lines
2.6 KiB
Lua
-- primitive for reading files from a file system (or, later, network)
|
|
-- returns a channel or nil on error
|
|
-- read lines from the channel using :recv()
|
|
-- recv() on the channel will indicate end of file.
|
|
function start_reading(fs, filename)
|
|
local result = task.Channel:new()
|
|
local infile = io.open(filename)
|
|
if infile == nil then return nil end
|
|
task.spawn(reading_task, infile, result)
|
|
return result
|
|
end
|
|
|
|
function reading_task(infile, chanout)
|
|
for line in infile:lines() do
|
|
chanout:send(line)
|
|
end
|
|
chanout:send(nil) -- eof
|
|
end
|
|
|
|
-- primitive for writing files to a file system (or, later, network)
|
|
-- returns a channel or nil on error
|
|
-- write to the channel using :send()
|
|
-- indicate you're done writing by calling :close()
|
|
-- file will not be externally visible until :close()
|
|
function start_writing(fs, filename)
|
|
if filename == nil then
|
|
error('start_writing requires two arguments: a file-system (nil for real disk) and a filename')
|
|
end
|
|
local result = task.Channel:new()
|
|
local initial_filename = temporary_filename_in_same_volume(filename)
|
|
local outfile = io.open(initial_filename, 'w')
|
|
if outfile == nil then return nil end
|
|
result.close = function()
|
|
result:send(nil) -- end of file
|
|
outfile:close()
|
|
os.rename(initial_filename, filename)
|
|
end
|
|
task.spawn(writing_task, outfile, result)
|
|
return result
|
|
end
|
|
|
|
function temporary_filename_in_same_volume(filename)
|
|
-- opening in same directory will hopefully keep it on the same volume,
|
|
-- so that a future rename works
|
|
local i = 1
|
|
while true do
|
|
temporary_filename = 'teliva_tmp_'..filename..'_'..i
|
|
if io.open(temporary_filename) == nil then
|
|
-- file doesn't exist yet; create a placeholder and return it
|
|
local handle = io.open(temporary_filename, 'w')
|
|
if handle == nil then
|
|
error("this is unexpected; I can't create temporary files..")
|
|
end
|
|
handle:close()
|
|
return temporary_filename
|
|
end
|
|
i = i+1
|
|
end
|
|
end
|
|
|
|
function writing_task(outfile, chanin)
|
|
while true do
|
|
local line = chanin:recv()
|
|
if line == nil then break end -- end of file
|
|
outfile:write(line)
|
|
end
|
|
end
|
|
|
|
-- start_reading reads line by line by default
|
|
-- this helper permits character-by-character reading
|
|
function character_by_character(chanin, buffer_size)
|
|
local chanout = task.Channel:new(buffer_size or 50)
|
|
task.spawn(character_splitting_task, chanin, chanout)
|
|
return chanout
|
|
end
|
|
|
|
function character_splitting_task(chanin, chanout)
|
|
while true do
|
|
local line = chanin:recv()
|
|
if line == nil then break end
|
|
local linesz = line:len()
|
|
for i=1,linesz do
|
|
chanout:send(line:sub(i, i))
|
|
end
|
|
end
|
|
chanout:send(nil) -- end of file
|
|
end
|