Advertisement
Stawlie0

Untitled

Oct 10th, 2023
586
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.58 KB | None | 0 0
  1. local computer = require("computer")
  2. local unicode = require("unicode")
  3.  
  4. local buffer = {}
  5. local metatable = {
  6.   __index = buffer,
  7.   __metatable = "file"
  8. }
  9.  
  10. function buffer.new(mode, stream)
  11.   local result = {
  12.     closed = false,
  13.     tty = false,
  14.     mode = {},
  15.     stream = stream,
  16.     bufferRead = "",
  17.     bufferWrite = "",
  18.     bufferSize = math.max(512, math.min(8 * 1024, computer.freeMemory() / 8)),
  19.     bufferMode = "full",
  20.     readTimeout = math.huge,
  21.   }
  22.   mode = mode or "r"
  23.   for i = 1, unicode.len(mode) do
  24.     result.mode[unicode.sub(mode, i, i)] = true
  25.   end
  26.   -- when stream closes, result should close first
  27.   -- when result closes, stream should close after
  28.   -- when stream closes, it is removed from the proc
  29.   stream.close = setmetatable({close = stream.close,parent = result},{__call = buffer.close})
  30.   return setmetatable(result, metatable)
  31. end
  32.  
  33. function buffer:close()
  34.   -- self is either the buffer, or the stream.close callable
  35.   local meta = getmetatable(self)
  36.   if meta == metatable.__metatable then
  37.     return self.stream:close()
  38.   end
  39.   local parent = self.parent
  40.  
  41.   if parent.mode.w or parent.mode.a then
  42.     parent:flush()
  43.   end
  44.   parent.closed = true
  45.   return self.close(parent.stream)
  46. end
  47.  
  48. function buffer:flush()
  49.   if #self.bufferWrite > 0 then
  50.     local tmp = self.bufferWrite
  51.     self.bufferWrite = ""
  52.     local result, reason = self.stream:write(tmp)
  53.     if not result then
  54.       return nil, reason or "bad file descriptor"
  55.     end
  56.   end
  57.  
  58.   return self
  59. end
  60.  
  61. function buffer:lines(...)
  62.   local args = table.pack(...)
  63.   return function()
  64.     local result = table.pack(self:read(table.unpack(args, 1, args.n)))
  65.     if not result[1] and result[2] then
  66.       error(result[2])
  67.     end
  68.     return table.unpack(result, 1, result.n)
  69.   end
  70. end
  71.  
  72. local function readChunk(self)
  73.   if computer.uptime() > self.timeout then
  74.     error("timeout")
  75.   end
  76.   local result, reason = self.stream:read(math.max(1,self.bufferSize))
  77.   if result then
  78.     self.bufferRead = self.bufferRead .. result
  79.     return self
  80.   else -- error or eof
  81.     return result, reason
  82.   end
  83. end
  84.  
  85. function buffer:readLine(chop, timeout)
  86.   self.timeout = timeout or (computer.uptime() + self.readTimeout)
  87.   local start = 1
  88.   while true do
  89.     local buf = self.bufferRead
  90.     local i = buf:find("[\r\n]", start)
  91.     local c = i and buf:sub(i,i)
  92.     local is_cr = c == "\r"
  93.     if i and (not is_cr or i < #buf) then
  94.       local n = buf:sub(i+1,i+1)
  95.       if is_cr and n == "\n" then
  96.         c = c .. n
  97.       end
  98.       local result = buf:sub(1, i - 1) .. (chop and "" or c)
  99.       self.bufferRead = buf:sub(i + #c)
  100.       return result
  101.     else
  102.       start = #self.bufferRead - (is_cr and 1 or 0)
  103.       local result, reason = readChunk(self)
  104.       if not result then
  105.         if reason then
  106.           return result, reason
  107.         else -- eof
  108.           result = #self.bufferRead > 0 and self.bufferRead or nil
  109.           self.bufferRead = ""
  110.           return result
  111.         end
  112.       end
  113.     end
  114.   end
  115. end
  116.  
  117. function buffer:read(...)
  118.   if not self.mode.r then
  119.     return nil, "read mode was not enabled for this stream"
  120.   end
  121.  
  122.   if self.mode.w or self.mode.a then
  123.     self:flush()
  124.   end
  125.  
  126.   if select("#", ...) == 0 then
  127.     return self:readLine(true)
  128.   end
  129.   return self:formatted_read(readChunk, ...)
  130. end
  131.  
  132. function buffer:setvbuf(mode, size)
  133.   mode = mode or self.bufferMode
  134.   size = size or self.bufferSize
  135.  
  136.   assert(mode == "no" or mode == "full" or mode == "line",
  137.     "bad argument #1 (no, full or line expected, got " .. tostring(mode) .. ")")
  138.   assert(mode == "no" or type(size) == "number",
  139.     "bad argument #2 (number expected, got " .. type(size) .. ")")
  140.  
  141.   self.bufferMode = mode
  142.   self.bufferSize = size
  143.  
  144.   return self.bufferMode, self.bufferSize
  145. end
  146.  
  147. function buffer:write(...)
  148.   if self.closed then
  149.     return nil, "bad file descriptor"
  150.   end
  151.   if not self.mode.w and not self.mode.a then
  152.     return nil, "write mode was not enabled for this stream"
  153.   end
  154.   local args = table.pack(...)
  155.   for i = 1, args.n do
  156.     if type(args[i]) == "number" then
  157.       args[i] = tostring(args[i])
  158.     end
  159.     checkArg(i, args[i], "string")
  160.   end
  161.  
  162.   for i = 1, args.n do
  163.     local arg = args[i]
  164.     local result, reason
  165.  
  166.     if self.bufferMode == "no" then
  167.       result, reason = self.stream:write(arg)
  168.     else
  169.       result, reason = buffer.buffered_write(self, arg)
  170.     end
  171.  
  172.     if not result then
  173.       return nil, reason
  174.     end
  175.   end
  176.  
  177.   return self
  178. end
  179.  
  180. require("package").delay(buffer, "/lib/core/full_buffer.lua")
  181.  
  182. return buffer
  183.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement