forgot to commit openos
This commit is contained in:
238
data/openos/lib/core/full_buffer.lua
Normal file
238
data/openos/lib/core/full_buffer.lua
Normal file
@@ -0,0 +1,238 @@
|
||||
local buffer = require("buffer")
|
||||
local unicode = require("unicode")
|
||||
|
||||
function buffer:getTimeout()
|
||||
return self.readTimeout
|
||||
end
|
||||
|
||||
function buffer:setTimeout(value)
|
||||
self.readTimeout = tonumber(value)
|
||||
end
|
||||
|
||||
function buffer:seek(whence, offset)
|
||||
whence = tostring(whence or "cur")
|
||||
assert(whence == "set" or whence == "cur" or whence == "end",
|
||||
"bad argument #1 (set, cur or end expected, got " .. whence .. ")")
|
||||
offset = offset or 0
|
||||
checkArg(2, offset, "number")
|
||||
assert(math.floor(offset) == offset, "bad argument #2 (not an integer)")
|
||||
|
||||
if self.mode.w or self.mode.a then
|
||||
self:flush()
|
||||
elseif whence == "cur" then
|
||||
offset = offset - #self.bufferRead
|
||||
end
|
||||
local result, reason = self.stream:seek(whence, offset)
|
||||
if result then
|
||||
self.bufferRead = ""
|
||||
return result
|
||||
else
|
||||
return nil, reason
|
||||
end
|
||||
end
|
||||
|
||||
function buffer:buffered_write(arg)
|
||||
local result, reason
|
||||
if self.bufferMode == "full" then
|
||||
if self.bufferSize - #self.bufferWrite < #arg then
|
||||
result, reason = self:flush()
|
||||
if not result then
|
||||
return nil, reason
|
||||
end
|
||||
end
|
||||
if #arg > self.bufferSize then
|
||||
result, reason = self.stream:write(arg)
|
||||
else
|
||||
self.bufferWrite = self.bufferWrite .. arg
|
||||
result = self
|
||||
end
|
||||
else--if self.bufferMode == "line" then
|
||||
local l
|
||||
repeat
|
||||
local idx = arg:find("\n", (l or 0) + 1, true)
|
||||
if idx then
|
||||
l = idx
|
||||
end
|
||||
until not idx
|
||||
if l or #arg > self.bufferSize then
|
||||
result, reason = self:flush()
|
||||
if not result then
|
||||
return nil, reason
|
||||
end
|
||||
end
|
||||
if l then
|
||||
result, reason = self.stream:write(arg:sub(1, l))
|
||||
if not result then
|
||||
return nil, reason
|
||||
end
|
||||
arg = arg:sub(l + 1)
|
||||
end
|
||||
if #arg > self.bufferSize then
|
||||
result, reason = self.stream:write(arg)
|
||||
else
|
||||
self.bufferWrite = self.bufferWrite .. arg
|
||||
result = self
|
||||
end
|
||||
end
|
||||
return result, reason
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------
|
||||
|
||||
function buffer:readNumber(readChunk)
|
||||
local len, sub
|
||||
if self.mode.b then
|
||||
len = rawlen
|
||||
sub = string.sub
|
||||
else
|
||||
len = unicode.len
|
||||
sub = unicode.sub
|
||||
end
|
||||
|
||||
local number_text = ""
|
||||
local white_done
|
||||
|
||||
local function peek()
|
||||
if len(self.bufferRead) == 0 then
|
||||
local result, reason = readChunk(self)
|
||||
if not result then
|
||||
return result, reason
|
||||
end
|
||||
end
|
||||
return sub(self.bufferRead, 1, 1)
|
||||
end
|
||||
|
||||
local function pop()
|
||||
local n = sub(self.bufferRead, 1, 1)
|
||||
self.bufferRead = sub(self.bufferRead, 2)
|
||||
return n
|
||||
end
|
||||
|
||||
while true do
|
||||
local peeked = peek()
|
||||
if not peeked then
|
||||
break
|
||||
end
|
||||
|
||||
if peeked:match("[%s]") then
|
||||
if white_done then
|
||||
break
|
||||
end
|
||||
pop()
|
||||
else
|
||||
white_done = true
|
||||
if not tonumber(number_text .. peeked .. "0") then
|
||||
break
|
||||
end
|
||||
number_text = number_text .. pop() -- add pop to number_text
|
||||
end
|
||||
end
|
||||
|
||||
return tonumber(number_text)
|
||||
end
|
||||
|
||||
function buffer:readBytesOrChars(readChunk, n)
|
||||
n = math.max(n, 0)
|
||||
local len, sub
|
||||
if self.mode.b then
|
||||
len = rawlen
|
||||
sub = string.sub
|
||||
else
|
||||
len = unicode.len
|
||||
sub = unicode.sub
|
||||
end
|
||||
local data = ""
|
||||
while true do
|
||||
local current_data_len = len(data)
|
||||
local needed = n - current_data_len
|
||||
if needed < 1 then
|
||||
break
|
||||
end
|
||||
-- if the buffer is empty OR there is only 1 char left, read next chunk
|
||||
-- this is to protect that last byte from bad unicode
|
||||
if #self.bufferRead == 0 then
|
||||
local result, reason = readChunk(self)
|
||||
if not result then
|
||||
if reason then
|
||||
return result, reason
|
||||
else -- eof
|
||||
return current_data_len > 0 and data or nil
|
||||
end
|
||||
end
|
||||
end
|
||||
local splice = self.bufferRead
|
||||
if len(self.bufferRead) > needed then
|
||||
splice = sub(self.bufferRead, 1, needed)
|
||||
if len(splice) ~= needed then
|
||||
-- this can happen if the stream does not represent valid utf8 sequences
|
||||
-- we could search the string for the bad sequence but regardless, we're going to just return the raw data
|
||||
splice = self.bufferRead -- yes this is more than the user is asking for, but this is better than corrupting the stream
|
||||
end
|
||||
-- else -- we will read more chunks
|
||||
end
|
||||
data = data .. splice
|
||||
self.bufferRead = string.sub(self.bufferRead, #splice + 1)
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
||||
function buffer:readAll(readChunk)
|
||||
repeat
|
||||
local result, reason = readChunk(self)
|
||||
if not result and reason then
|
||||
return result, reason
|
||||
end
|
||||
until not result -- eof
|
||||
local result = self.bufferRead
|
||||
self.bufferRead = ""
|
||||
return result
|
||||
end
|
||||
|
||||
function buffer:formatted_read(readChunk, ...)
|
||||
self.timeout = require("computer").uptime() + self.readTimeout
|
||||
local function read(n, format)
|
||||
if type(format) == "number" then
|
||||
return self:readBytesOrChars(readChunk, format)
|
||||
else
|
||||
local first_char_index = 1
|
||||
if type(format) ~= "string" then
|
||||
error("bad argument #" .. n .. " (invalid option)")
|
||||
elseif unicode.sub(format, 1, 1) == "*" then
|
||||
first_char_index = 2
|
||||
end
|
||||
format = unicode.sub(format, first_char_index, first_char_index)
|
||||
if format == "n" then
|
||||
return self:readNumber(readChunk)
|
||||
elseif format == "l" then
|
||||
return self:readLine(true, self.timeout)
|
||||
elseif format == "L" then
|
||||
return self:readLine(false, self.timeout)
|
||||
elseif format == "a" then
|
||||
return self:readAll(readChunk)
|
||||
else
|
||||
error("bad argument #" .. n .. " (invalid format)")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local results = {}
|
||||
local formats = table.pack(...)
|
||||
for i = 1, formats.n do
|
||||
local result, reason = read(i, formats[i])
|
||||
if result then
|
||||
results[i] = result
|
||||
elseif reason then
|
||||
return nil, reason
|
||||
end
|
||||
end
|
||||
return table.unpack(results, 1, formats.n)
|
||||
end
|
||||
|
||||
function buffer:size()
|
||||
local len = self.mode.b and rawlen or unicode.len
|
||||
local size = len(self.bufferRead)
|
||||
if self.stream.size then
|
||||
size = size + self.stream:size()
|
||||
end
|
||||
return size
|
||||
end
|
||||
Reference in New Issue
Block a user