|
|
- -- -----------------------------------------------------------------------------
- -- -- LTN12 - Filters, sources, sinks and pumps.
- -- -- LuaSocket toolkit.
- -- -- Author: Diego Nehab
- -- -----------------------------------------------------------------------------
-
- -- -----------------------------------------------------------------------------
- -- -- Declare module
- -- -----------------------------------------------------------------------------
- -- local string = require("string")
- -- local table = require("table")
- -- local unpack = unpack or table.unpack
- -- local base = _G
- -- local _M = {}
- -- if module then -- heuristic for exporting a global package table
- -- ltn12 = _M
- -- end
- -- local filter,source,sink,pump = {},{},{},{}
-
- -- _M.filter = filter
- -- _M.source = source
- -- _M.sink = sink
- -- _M.pump = pump
-
- -- local unpack = unpack or table.unpack
- -- local select = base.select
-
- -- -- 2048 seems to be better in windows...
- -- _M.BLOCKSIZE = 2048
- -- _M._VERSION = "LTN12 1.0.3"
-
- -- -----------------------------------------------------------------------------
- -- -- Filter stuff
- -- -----------------------------------------------------------------------------
- -- -- returns a high level filter that cycles a low-level filter
- -- function filter.cycle(low, ctx, extra)
- -- base.assert(low)
- -- return function(chunk)
- -- local ret
- -- ret, ctx = low(ctx, chunk, extra)
- -- return ret
- -- end
- -- end
-
- -- -- chains a bunch of filters together
- -- -- (thanks to Wim Couwenberg)
- -- function filter.chain(...)
- -- local arg = {...}
- -- local n = base.select('#',...)
- -- local top, index = 1, 1
- -- local retry = ""
- -- return function(chunk)
- -- retry = chunk and retry
- -- while true do
- -- if index == top then
- -- chunk = arg[index](chunk)
- -- if chunk == "" or top == n then return chunk
- -- elseif chunk then index = index + 1
- -- else
- -- top = top+1
- -- index = top
- -- end
- -- else
- -- chunk = arg[index](chunk or "")
- -- if chunk == "" then
- -- index = index - 1
- -- chunk = retry
- -- elseif chunk then
- -- if index == n then return chunk
- -- else index = index + 1 end
- -- else base.error("filter returned inappropriate nil") end
- -- end
- -- end
- -- end
- -- end
-
- -- -----------------------------------------------------------------------------
- -- -- Source stuff
- -- -----------------------------------------------------------------------------
- -- -- create an empty source
- -- local function empty()
- -- return nil
- -- end
-
- -- function source.empty()
- -- return empty
- -- end
-
- -- -- returns a source that just outputs an error
- -- function source.error(err)
- -- return function()
- -- return nil, err
- -- end
- -- end
-
- -- -- creates a file source
- -- function source.file(handle, io_err)
- -- if handle then
- -- return function()
- -- local chunk = handle:read(_M.BLOCKSIZE)
- -- if not chunk then handle:close() end
- -- return chunk
- -- end
- -- else return source.error(io_err or "unable to open file") end
- -- end
-
- -- -- turns a fancy source into a simple source
- -- function source.simplify(src)
- -- base.assert(src)
- -- return function()
- -- local chunk, err_or_new = src()
- -- src = err_or_new or src
- -- if not chunk then return nil, err_or_new
- -- else return chunk end
- -- end
- -- end
-
- -- -- creates string source
- -- function source.string(s)
- -- if s then
- -- local i = 1
- -- return function()
- -- local chunk = string.sub(s, i, i+_M.BLOCKSIZE-1)
- -- i = i + _M.BLOCKSIZE
- -- if chunk ~= "" then return chunk
- -- else return nil end
- -- end
- -- else return source.empty() end
- -- end
-
- -- -- creates rewindable source
- -- function source.rewind(src)
- -- base.assert(src)
- -- local t = {}
- -- return function(chunk)
- -- if not chunk then
- -- chunk = table.remove(t)
- -- if not chunk then return src()
- -- else return chunk end
- -- else
- -- table.insert(t, chunk)
- -- end
- -- end
- -- end
-
- -- -- chains a source with one or several filter(s)
- -- function source.chain(src, f, ...)
- -- if ... then f=filter.chain(f, ...) end
- -- base.assert(src and f)
- -- local last_in, last_out = "", ""
- -- local state = "feeding"
- -- local err
- -- return function()
- -- if not last_out then
- -- base.error('source is empty!', 2)
- -- end
- -- while true do
- -- if state == "feeding" then
- -- last_in, err = src()
- -- if err then return nil, err end
- -- last_out = f(last_in)
- -- if not last_out then
- -- if last_in then
- -- base.error('filter returned inappropriate nil')
- -- else
- -- return nil
- -- end
- -- elseif last_out ~= "" then
- -- state = "eating"
- -- if last_in then last_in = "" end
- -- return last_out
- -- end
- -- else
- -- last_out = f(last_in)
- -- if last_out == "" then
- -- if last_in == "" then
- -- state = "feeding"
- -- else
- -- base.error('filter returned ""')
- -- end
- -- elseif not last_out then
- -- if last_in then
- -- base.error('filter returned inappropriate nil')
- -- else
- -- return nil
- -- end
- -- else
- -- return last_out
- -- end
- -- end
- -- end
- -- end
- -- end
-
- -- -- creates a source that produces contents of several sources, one after the
- -- -- other, as if they were concatenated
- -- -- (thanks to Wim Couwenberg)
- -- function source.cat(...)
- -- local arg = {...}
- -- local src = table.remove(arg, 1)
- -- return function()
- -- while src do
- -- local chunk, err = src()
- -- if chunk then return chunk end
- -- if err then return nil, err end
- -- src = table.remove(arg, 1)
- -- end
- -- end
- -- end
-
- -- -----------------------------------------------------------------------------
- -- -- Sink stuff
- -- -----------------------------------------------------------------------------
- -- -- creates a sink that stores into a table
- -- function sink.table(t)
- -- t = t or {}
- -- local f = function(chunk, err)
- -- if chunk then table.insert(t, chunk) end
- -- return 1
- -- end
- -- return f, t
- -- end
-
- -- -- turns a fancy sink into a simple sink
- -- function sink.simplify(snk)
- -- base.assert(snk)
- -- return function(chunk, err)
- -- local ret, err_or_new = snk(chunk, err)
- -- if not ret then return nil, err_or_new end
- -- snk = err_or_new or snk
- -- return 1
- -- end
- -- end
-
- -- -- creates a file sink
- -- function sink.file(handle, io_err)
- -- if handle then
- -- return function(chunk, err)
- -- if not chunk then
- -- handle:close()
- -- return 1
- -- else return handle:write(chunk) end
- -- end
- -- else return sink.error(io_err or "unable to open file") end
- -- end
-
- -- -- creates a sink that discards data
- -- local function null()
- -- return 1
- -- end
-
- -- function sink.null()
- -- return null
- -- end
-
- -- -- creates a sink that just returns an error
- -- function sink.error(err)
- -- return function()
- -- return nil, err
- -- end
- -- end
-
- -- -- chains a sink with one or several filter(s)
- -- function sink.chain(f, snk, ...)
- -- if ... then
- -- local args = { f, snk, ... }
- -- snk = table.remove(args, #args)
- -- f = filter.chain(unpack(args))
- -- end
- -- base.assert(f and snk)
- -- return function(chunk, err)
- -- if chunk ~= "" then
- -- local filtered = f(chunk)
- -- local done = chunk and ""
- -- while true do
- -- local ret, snkerr = snk(filtered, err)
- -- if not ret then return nil, snkerr end
- -- if filtered == done then return 1 end
- -- filtered = f(done)
- -- end
- -- else return 1 end
- -- end
- -- end
-
- -- -----------------------------------------------------------------------------
- -- -- Pump stuff
- -- -----------------------------------------------------------------------------
- -- -- pumps one chunk from the source to the sink
- -- function pump.step(src, snk)
- -- local chunk, src_err = src()
- -- local ret, snk_err = snk(chunk, src_err)
- -- if chunk and ret then return 1
- -- else return nil, src_err or snk_err end
- -- end
-
- -- -- pumps all data from a source to a sink, using a step function
- -- function pump.all(src, snk, step)
- -- base.assert(src and snk)
- -- step = step or pump.step
- -- while true do
- -- local ret, err = step(src, snk)
- -- if not ret then
- -- if err then return nil, err
- -- else return 1 end
- -- end
- -- end
- -- end
-
- -- return _M
|