summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/util-soc-imp-ltn12.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/util-soc-imp-ltn12.lua')
-rw-r--r--tex/context/base/mkiv/util-soc-imp-ltn12.lua387
1 files changed, 387 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/util-soc-imp-ltn12.lua b/tex/context/base/mkiv/util-soc-imp-ltn12.lua
new file mode 100644
index 000000000..54110ab7a
--- /dev/null
+++ b/tex/context/base/mkiv/util-soc-imp-ltn12.lua
@@ -0,0 +1,387 @@
+-- original file : ltn12.lua
+-- for more into : see util-soc.lua
+
+local select, unpack = select, unpack
+local insert, remove = table.insert, table.remove
+local sub = string.sub
+
+local function report(fmt,first,...)
+ if logs then
+ report = logs and logs.reporter("ltn12")
+ report(fmt,first,...)
+ elseif fmt then
+ fmt = "ltn12: " .. fmt
+ if first then
+ print(format(fmt,first,...))
+ else
+ print(fmt)
+ end
+ end
+end
+
+local filter = { }
+local source = { }
+local sink = { }
+local pump = { }
+
+local ltn12 = {
+
+ _VERSION = "LTN12 1.0.3",
+
+ BLOCKSIZE = 2048,
+
+ filter = filter,
+ source = source,
+ sink = sink,
+ pump = pump,
+
+ report = report,
+
+}
+
+-- returns a high level filter that cycles a low-level filter
+
+function filter.cycle(low, ctx, extra)
+ if low then
+ return function(chunk)
+ return (low(ctx, chunk, extra))
+ end
+ end
+end
+
+-- chains a bunch of filters together
+
+function filter.chain(...)
+ local arg = { ... }
+ local n = select('#',...)
+ local top = 1
+ local index = 1
+ local retry = ""
+ return function(chunk)
+ retry = chunk and retry
+ while true do
+ local action = arg[index]
+ if index == top then
+ chunk = action(chunk)
+ if chunk == "" or top == n then
+ return chunk
+ elseif chunk then
+ index = index + 1
+ else
+ top = top + 1
+ index = top
+ end
+ else
+ chunk = action(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
+ report("error: filter returned inappropriate 'nil'")
+ return
+ end
+ end
+ end
+ end
+end
+
+-- create an empty source
+
+local function empty()
+ return nil
+end
+
+function source.empty()
+ return empty
+end
+
+-- returns a source that just outputs an error
+
+local function sourceerror(err)
+ return function()
+ return nil, err
+ end
+end
+
+source.error = sourceerror
+
+-- creates a file source
+
+function source.file(handle, io_err)
+ if handle then
+ local blocksize = ltn12.BLOCKSIZE
+ return function()
+ local chunk = handle:read(blocksize)
+ if not chunk then
+ handle:close()
+ end
+ return chunk
+ end
+ else
+ return sourceerror(io_err or "unable to open file")
+ end
+end
+
+-- turns a fancy source into a simple source
+
+function source.simplify(src)
+ return function()
+ local chunk, err_or_new = src()
+ if err_or_new then
+ src = err_or_new
+ end
+ if chunk then
+ return chunk
+ else
+ return nil, err_or_new
+ end
+ end
+end
+
+-- creates string source
+
+function source.string(s)
+ if s then
+ local blocksize = ltn12.BLOCKSIZE
+ local i = 1
+ return function()
+ local nexti = i + blocksize
+ local chunk = sub(s, i, nexti - 1)
+ i = nexti
+ if chunk ~= "" then
+ return chunk
+ else
+ return nil
+ end
+ end
+ else return source.empty() end
+end
+
+-- creates rewindable source
+
+function source.rewind(src)
+ local t = { }
+ return function(chunk)
+ if chunk then
+ insert(t, chunk)
+ else
+ chunk = remove(t)
+ if chunk then
+ return chunk
+ else
+ return src()
+ end
+ end
+ end
+end
+
+-- chains a source with one or several filter(s)
+
+function source.chain(src, f, ...)
+ if ... then
+ f = filter.chain(f, ...)
+ end
+ local last_in = ""
+ local last_out = ""
+ local state = "feeding"
+ local err
+ return function()
+ if not last_out then
+ report("error: source is empty")
+ return
+ 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
+ report("error: filter returned inappropriate 'nil'")
+ end
+ return nil
+ 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
+ report("error: filter returned nothing")
+ return
+ end
+ elseif not last_out then
+ if last_in then
+ report("filter returned inappropriate 'nil'")
+ end
+ return nil
+ 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
+
+function source.cat(...)
+ local arg = { ... }
+ local src = 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 = remove(arg,1)
+ end
+ end
+end
+
+-- creates a sink that stores into a table
+
+function sink.table(t)
+ if not t then
+ t = { }
+ end
+ local f = function(chunk, err)
+ if chunk then
+ insert(t, chunk)
+ end
+ return 1
+ end
+ return f, t
+end
+
+-- turns a fancy sink into a simple sink
+
+function sink.simplify(snk)
+ return function(chunk, err)
+ local ret, err_or_new = snk(chunk, err)
+ if not ret then
+ return nil, err_or_new
+ end
+ if err_or_new then
+ snk = err_or_new
+ end
+ return 1
+ 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
+
+local function sinkerror(err)
+ return function()
+ return nil, err
+ end
+end
+
+sink.error = sinkerror
+
+-- 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 sinkerror(io_err or "unable to open file")
+ end
+end
+
+-- chains a sink with one or several filter(s)
+
+function sink.chain(f, snk, ...)
+ if ... then
+ local args = { f, snk, ... }
+ snk = remove(args, #args)
+ f = filter.chain(unpack(args))
+ end
+ 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
+
+-- 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)
+ if not step then
+ step = pump.step
+ end
+ 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
+
+package.loaded["ltn12"] = ltn12
+
+return ltn12