diff options
author | Hans Hagen <pragma@wxs.nl> | 2021-06-24 19:37:45 +0200 |
---|---|---|
committer | Context Git Mirror Bot <phg@phi-gamma.net> | 2021-06-24 19:37:45 +0200 |
commit | 820657bb1e9acfb36f24dfa8801526b0d5f2b464 (patch) | |
tree | fc93fd3936e84b9b0a6402719e185d35e332eee9 /tex/context/base/mkiv | |
parent | 4272a26c49cbfee8917e5272fc0f964cbcfc4b03 (diff) | |
download | context-820657bb1e9acfb36f24dfa8801526b0d5f2b464.tar.gz |
2021-06-24 18:52:00
Diffstat (limited to 'tex/context/base/mkiv')
38 files changed, 1333 insertions, 507 deletions
diff --git a/tex/context/base/mkiv/back-exp.lua b/tex/context/base/mkiv/back-exp.lua index 5928da538..51c32ec1d 100644 --- a/tex/context/base/mkiv/back-exp.lua +++ b/tex/context/base/mkiv/back-exp.lua @@ -1640,7 +1640,7 @@ do d.__i__ = n data[n] = d elseif content == " " or content == "" then - if di.tg == "mspace" then + if d.tg == "mspace" then -- we append or prepend a space to a preceding or following mtext local parent = di.__p__ local index = di.__i__ -- == i diff --git a/tex/context/base/mkiv/cldf-ini.lua b/tex/context/base/mkiv/cldf-ini.lua index f95ac301c..a69b2d707 100644 --- a/tex/context/base/mkiv/cldf-ini.lua +++ b/tex/context/base/mkiv/cldf-ini.lua @@ -400,19 +400,22 @@ local registerscanner if CONTEXTLMTXMODE > 0 then -- always permanent but we can consider to obey permanent==false + -- todo: make bitset instead of keys (nil is skipped anyway) + local function toflags(specification) - local protected = specification.protected and "protected" -- or "" + local protected = specification.protected and "protected" + local untraced = specification.untraced and "untraced" local usage = specification.usage if usage == "value" then - return "global", "value", "permanent", protected + return "global", "value", "permanent", "untraced", protected elseif usage == "condition" then - return "global", "conditional", "permanent", protected + return "global", "conditional", "permanent", "untraced", protected elseif specification.frozen then - return "global", "frozen", protected + return "global", "frozen", untraced, protected elseif specification.permanent == false or specification.onlyonce then -- for now onlyonce here - return "global", protected + return "global", untraced, protected else - return "global", "permanent", protected + return "global", "permanent", untraced, protected end end @@ -422,6 +425,7 @@ local registerscanner if CONTEXTLMTXMODE > 0 then storedscanners[name] = n namesofscanners[n] = name name = specification.public and name or (privatenamespace .. name) + -- print(name,n,toflags(specification)) setluatoken(name,n,toflags(specification)) end diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index 29bb55997..5ae1a881c 100644 --- a/tex/context/base/mkiv/cont-new.mkiv +++ b/tex/context/base/mkiv/cont-new.mkiv @@ -13,7 +13,7 @@ % \normalend % uncomment this to get the real base runtime -\newcontextversion{2021.06.14 17:06} +\newcontextversion{2021.06.24 18:50} %D This file is loaded at runtime, thereby providing an excellent place for hacks, %D patches, extensions and new features. There can be local overloads in cont-loc diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index 4e6e0dcb9..20d33af39 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -45,7 +45,7 @@ %D {YYYY.MM.DD HH:MM} format. \edef\contextformat {\jobname} -\edef\contextversion{2021.06.14 17:06} +\edef\contextversion{2021.06.24 18:50} %D Kind of special: diff --git a/tex/context/base/mkiv/data-dec.lua b/tex/context/base/mkiv/data-dec.lua new file mode 100644 index 000000000..2a62b7dd9 --- /dev/null +++ b/tex/context/base/mkiv/data-dec.lua @@ -0,0 +1,56 @@ +if not modules then modules = { } end modules ['data-dec'] = { + version = 1.001, + comment = "companion to luat-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local loaddata = io.loaddata +local suffix = file.suffix +local resultof = os.resultof + +local decompressors = { } +resolvers.decompressors = decompressors + +local decompresslzma = nil +local decompressgzip = gzip.decompress + +local function decompressed(k) + local s = suffix(k) + if s == "xz" then + if decompresslzma == nil then + local lzma = require(resolvers.findfile("libs-imp-lzma.lmt")) + if lzma then + local decompress = lzma.decompress + decompresslzma = function(name) + return decompress(loaddata(k)) + end + else + decompresslzma = function(name) + -- todo: use a proper runner + return resultof("xz -d -c -q -q " .. name) + end + end + end + return decompresslzma(k) + elseif s == "gz" then + return decompressgzip(loaddata(k)) + end +end + +local cache = table.setmetatableindex(function(t,k) + local v = decompressed(k) or false + t[k] = v + return v +end) + +decompressors.decompress = decompress + +function decompressors.register(filename) + return cache[filename] +end + +function decompressors.unregister(filename) + cache[filename] = nil +end diff --git a/tex/context/base/mkiv/data-tar.lua b/tex/context/base/mkiv/data-tar.lua new file mode 100644 index 000000000..45de749b6 --- /dev/null +++ b/tex/context/base/mkiv/data-tar.lua @@ -0,0 +1,236 @@ +if not modules then modules = { } end modules ['data-tar'] = { + version = 1.001, + comment = "companion to luat-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local format, find, match = string.format, string.find, string.match + +local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end) + +local report_tar = logs.reporter("resolvers","tar") + +--[[ldx-- +<p>We use a url syntax for accessing the tar file itself and file in it:</p> + +<typing> +tar:///oeps.tar?name=bla/bla.tex +tar:///oeps.tar?tree=tex/texmf-local +</typing> +--ldx]]-- + +local resolvers = resolvers +local findfile = resolvers.findfile +local registerfile = resolvers.registerfile +local splitmethod = resolvers.splitmethod +local starttiming = resolvers.starttiming +local stoptiming = resolvers.stoptiming + +local urlquery = url.query + +--- hm, zip sits in the global namespace, but tar doesn't + +local tar = utilities.tar or { } +utilities.tar = tar -- not needed + +local archives = tar.archives or { } +tar.archives = archives + +local registeredfiles = tar.registeredfiles or { } +tar.registeredfiles = registeredfiles + +-- foo.tar.xz : done +-- foo.tar.gz : todo +-- foo.tar : done + +local hashtar, fetchtar, wipetar do + + local suffix = file.suffix -- hassuffix .. no need to split + + local tarfiles = utilities.tar.file + local tarstrings = utilities.tar.string + + local hashtarfile = tar.files.hash + local fetchtarfile = tar.files.fetch + + local hashtarstring = tar.strings.hash + local fetchtarstring = tar.strings.fetch + + local register = resolvers.decompressors.register + + hashtar = function(archive,strip) + local a = register(archive) + if a then + return hashtarstring(a,archive) + else + return hashtarfile(archive,archive) + end + end + + fetchtar = function(archive,filename,list) + local a = register(archive) + if a then + return fetchtarstring(a,filename,list) + else + return fetchtarfile(archive,filename,list) + end + end + + wipetar = resolvers.decompressors.unregister + +end + +local function validfile(archive,name) + return archive[name] +end + +local function openarchive(name) + if not name or name == "" then + return nil + else + local arch = archives[name] + if not arch then + local full = findfile(name) or "" + arch = full ~= "" and hashtar(full,name) or false + archives[name] = arch + end + return arch + end +end + +local function closearchive(name) + if not name or (name == "" and archives[name]) then + archives[name] = nil + wipetar(name) + end +end + +tar.openarchive = openarchive +tar.closearchive = closearchive + +function resolvers.locators.tar(specification) + local archive = specification.filename + local tarfile = archive and archive ~= "" and openarchive(archive) + if trace_locating then + if tarfile then + report_tar("locator: archive %a found",archive) + else + report_tar("locator: archive %a not found",archive) + end + end +end + +function resolvers.concatinators.tar(tarfile,path,name) -- ok ? + if not path or path == "" then + return format('%s?name=%s',tarfile,name) + else + return format('%s?name=%s/%s',tarfile,path,name) + end +end + +local finders = resolvers.finders +local notfound = finders.notfound + +function finders.tar(specification) + local original = specification.original + local archive = specification.filename + if archive then + local query = urlquery(specification.query) + local queryname = query.name + if queryname then + local tfile = openarchive(archive) + if tfile then + if trace_locating then + report_tar("finder: archive %a found",archive) + end + if validfile(tfile,queryname) then + if trace_locating then + report_tar("finder: file %a found",queryname) + end + return specification.original + elseif trace_locating then + report_tar("finder: file %a not found",queryname) + end + elseif trace_locating then + report_tar("finder: unknown archive %a",archive) + end + end + end + if trace_locating then + report_tar("finder: %a not found",original) + end + return notfound() +end + +local openers = resolvers.openers +local notfound = openers.notfound +local textopener = openers.helpers.textopener + +function openers.tar(specification) + local original = specification.original + local archive = specification.filename + if archive then + local query = urlquery(specification.query) + local queryname = query.name + if queryname then + local tfile = openarchive(archive) + if tfile then + if trace_locating then + report_tar("opener; archive %a opened",archive) + end + local data = fetchtar(archive,queryname,tfile) + if data then + if trace_locating then + report_tar("opener: file %a found",queryname) + end + return textopener('tar',original,data) -- a string handle + elseif trace_locating then + report_tar("opener: file %a not found",queryname) + end + elseif trace_locating then + report_tar("opener: unknown archive %a",archive) + end + end + end + if trace_locating then + report_tar("opener: %a not found",original) + end + return notfound() +end + +loaders = resolvers.loaders +local notfound = loaders.notfound + +function loaders.tar(specification) + local original = specification.original + local archive = specification.filename + if archive then + local query = urlquery(specification.query) + local queryname = query.name + if queryname then + local tfile = openarchive(archive) + if tfile then + if trace_locating then + report_tar("loader: archive %a opened",archive) + end + local data = fetchtar(archive,queryname,tfile) + if data then + if trace_locating then + report_tar("loader; file %a loaded",original) + end + return true, data, #data + elseif trace_locating then + report_tar("loader: file %a not found",queryname) + end + elseif trace_locating then + report_tar("loader; unknown archive %a",archive) + end + end + end + if trace_locating then + report_tar("loader: %a not found",original) + end + return notfound() +end diff --git a/tex/context/base/mkiv/data-use.lua b/tex/context/base/mkiv/data-use.lua index a7ca2389e..168b62201 100644 --- a/tex/context/base/mkiv/data-use.lua +++ b/tex/context/base/mkiv/data-use.lua @@ -82,14 +82,14 @@ function statistics.savefmtstatus(texname,formatbanner,sourcefile,banner) -- tex functionality = LUATEXFUNCTIONALITY, } io.savedata(luvname,table.serialize(luvdata,true)) - lua.registerfinalizer(function() + lua.registerinitexfinalizer(function() if jit then logs.report("format banner","%s lua: %s jit",banner,LUAVERSION) else logs.report("format banner","%s lua: %s",banner,LUAVERSION) end logs.newline() - end) + end, "show banner") end end diff --git a/tex/context/base/mkiv/data-zip.lua b/tex/context/base/mkiv/data-zip.lua index 8d914b842..1a9310f17 100644 --- a/tex/context/base/mkiv/data-zip.lua +++ b/tex/context/base/mkiv/data-zip.lua @@ -70,10 +70,10 @@ if zipfiles then local readstring = streams.readstring local streamsize = streams.size - local metatable = { + local metatable = { -- irrelevant as the streams proivide the methods .. a leftover? close = streams.close, read = function(stream,n) - readstring(stream,n == "*a" and streamsize(stream) or n) + readstring(stream,n == "*a" and streamsize(stream) or n) -- no return ? end } diff --git a/tex/context/base/mkiv/font-cff.lua b/tex/context/base/mkiv/font-cff.lua index ff87292ba..8b01d92b7 100644 --- a/tex/context/base/mkiv/font-cff.lua +++ b/tex/context/base/mkiv/font-cff.lua @@ -572,6 +572,11 @@ do stack[top] = -(byte(b0)-251)*256 - byte(b1) - 108 end + -- local p_float = P("\255") * C(1) * C(1) * C(1) * C(1) / function(b0,b1,b2,b3) + -- top = top + 1 + -- stack[top] = 0 + -- end + local p_short = P("\28") * C(1) * C(1) / function(b1,b2) -- -32768 .. +32767 : b1<<8 | b2 top = top + 1 @@ -607,6 +612,7 @@ do + p_nibbles + p_single + p_double + -- + p_float + p_unsupported )^1 @@ -1825,13 +1831,13 @@ do stack[top] = -t*256 + 64148 - tab[i+1] i = i + 2 else - -- a 16.16 float - local n = 0x100 * tab[i+1] + tab[i+2] - if n >= 0x8000 then - stack[top] = n - 0x10000 + (0x100 * tab[i+3] + tab[i+4])/0xFFFF - else - stack[top] = n + (0x100 * tab[i+3] + tab[i+4])/0xFFFF + -- a 16.16 float (used for italic but pretty unreliable) + local n1 = 0x100 * tab[i+1] + tab[i+2] + local n2 = 0x100 * tab[i+3] + tab[i+4] + if n1 >= 0x8000 then + n1 = n1 - 0x10000 end + stack[top] = n1 + n2/0xFFFF i = i + 5 end elseif t == 28 then diff --git a/tex/context/base/mkiv/font-imp-math.lua b/tex/context/base/mkiv/font-imp-math.lua index d2294e93c..c0185ca34 100644 --- a/tex/context/base/mkiv/font-imp-math.lua +++ b/tex/context/base/mkiv/font-imp-math.lua @@ -108,7 +108,8 @@ function fonts.helpers.mathscriptslots(tfmdata,textcode) end end end -local function initialize(tfmdata,key,value) + +local function initialize(tfmdata,value) if value then local rawdata = tfmdata.shared.rawdata local rawresources = rawdata and rawdata.resources diff --git a/tex/context/base/mkiv/font-imp-tweaks.lua b/tex/context/base/mkiv/font-imp-tweaks.lua index 9cbda97fa..6d522e48b 100644 --- a/tex/context/base/mkiv/font-imp-tweaks.lua +++ b/tex/context/base/mkiv/font-imp-tweaks.lua @@ -10,10 +10,15 @@ if not context then return end local addfeature = fonts.handlers.otf.addfeature +-- The mapping directives avoids a check and copying of the (kind of special code +-- mapping tables. + addfeature { name = "uppercasing", type = "substitution", prepend = true, + mapping = true, + -- valid = function() return true end, data = characters.uccodes } @@ -21,5 +26,115 @@ addfeature { name = "lowercasing", type = "substitution", prepend = true, + mapping = true, + -- valid = function() return true end, data = characters.lccodes } + +if CONTEXTLMTXMODE > 0 then + + local nuts = nodes.nuts + local isnextchar = nuts.isnextchar + local getdisc = nuts.getdisc + local setchar = nuts.setchar + + local disc_code = nodes.nodecodes.disc + + local lccodes = characters.lccodes + local uccodes = characters.uccodes + + function fonts.handlers.otf.handlers.ctx_camelcasing(head,dataset,sequence,initialrl,font,dynamic) + local first = false + local current = head + -- local scale = 1000 + -- local xscale = 1000 + -- local yscale = 1000 + local function check(current) + while current do + -- scale, xscale, yscale = getscales(current) + local nxt, char, id = isnextchar(current,font,dynamic) -- ,scale,xscale,yscale) + if char then + if first then + local lower = lccodes[char] + if lower ~= char then + setchar(current,lower) + end + else + local upper = uccodes[char] + if upper ~= char then + setchar(current,upper) + end + first = true + end + elseif id == disc_code then + local pre, post, replace = getdisc(current) + if pre then + check(pre) + end + if post then + check(post) + end + if replace then + check(replace) + end + else + first = false + end + current = nxt + end + end + check(current) + return head + end + + addfeature { + nocheck = true, + name = "camelcasing", + type = "ctx_camelcasing", + prepend = true, + data = "action", + } + +end + +do -- for the moment this is mostly a demo feature + + local digit = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" } + local single = { "'" } + local double = { '"' } + + local singleprime = 0x2032 -- "′" + local doubleprime = 0x2033 -- "″" + + addfeature { + -- nocheck = true, + name = "primes", + type = "chainsubstitution", + lookups = { + { + type = "substitution", + data = { ["'"] = singleprime }, + }, + { + type = "substitution", + data = { ["'"] = doubleprime }, + }, + }, + data = { + rules = { + { + before = { digit }, + current = { single }, + after = { digit }, + lookups = { 1 }, + }, + { + before = { digit }, + current = { single, single }, + lookups = { 2, 0 }, -- zero: gsub_remove + }, + }, + }, + } + +end diff --git a/tex/context/base/mkiv/font-osd.lua b/tex/context/base/mkiv/font-osd.lua index 2d0e685c1..a9ea878c0 100644 --- a/tex/context/base/mkiv/font-osd.lua +++ b/tex/context/base/mkiv/font-osd.lua @@ -118,7 +118,7 @@ local setstate = nuts.setstate local ischar = nuts.ischar -local insertnodeafter = nuts.insertafter +local insertnodeafter = nuts.insertafter local copy_node = nuts.copy local remove_node = nuts.remove local flushlist = nuts.flushlist @@ -130,7 +130,8 @@ local unsetvalue = attributes.unsetvalue local fontdata = fonts.hashes.identifiers -local a_syllabe = attributes.private('syllabe') +local a_syllabe = "syllable" -- attributes.private('syllabe') -- can be just a property key +local a_reordered = "reordered" -- attributes.private('reordered') -- can be just a property key local dotted_circle = 0x25CC local c_nbsp = 0x00A0 @@ -1332,7 +1333,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) if getchar(base) == c_nbsp then nbspaces = nbspaces - 1 if base == stop then - stop = getprev(stop) + stop = getprev(stop) end head = remove_node(head,base) flushnode(base) @@ -1514,7 +1515,7 @@ function handlers.devanagari_reorder_reph(head,start) start = startnext startattr = getprop(start,a_syllabe) break - elseif not c and ( vowel_modifier[char] or stress_tone_mark[char] ) then + elseif not c and (vowel_modifier[char] or stress_tone_mark[char]) then c = current end current = getnext(current) @@ -1616,10 +1617,8 @@ end -- return head, start, done -- end -local reordered_pre_base_reordering_consonants = { } -- shared ? not reset ? - function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start) - if reordered_pre_base_reordering_consonants[start] then + if getprop(start,a_reordered) then return head, start, true end local current = start -- we could cache attributes here @@ -1643,7 +1642,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start) setlink(start,next) setlink(current,start) -- setlink(current,start,next) -- maybe - reordered_pre_base_reordering_consonants[start] = true + setprop(start,"reordered",true) start = startnext return head, start, true -- elseif consonant[char] and (not getstate(current) or getstate(current,s_init)) then @@ -1679,7 +1678,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start) setlink(getprev(current),start) setlink(start,current) end - reordered_pre_base_reordering_consonants[start] = true + setprop(start,"reordered",true) start = startnext break end @@ -2251,20 +2250,20 @@ local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowe local already_below_mark -- = false local already_post_mark -- = false while dependent_vowel[v] do - local vowels = twopart_mark[v] or { v } - for k, v in next, vowels do - if pre_mark[v] and not already_pre_mark then - already_pre_mark = true - elseif above_mark[v] and not already_above_mark then - already_above_mark = true - elseif below_mark[v] and not already_below_mark then - already_below_mark = true - elseif post_mark[v] and not already_post_mark then - already_post_mark = true - else - return c - end - end + local vowels = twopart_mark[v] or { v } + for k, v in next, vowels do + if pre_mark[v] and not already_pre_mark then + already_pre_mark = true + elseif above_mark[v] and not already_above_mark then + already_above_mark = true + elseif below_mark[v] and not already_below_mark then + already_below_mark = true + elseif post_mark[v] and not already_post_mark then + already_post_mark = true + else + return c + end + end c = getnext(c) n = getnext(c) if not n then @@ -2440,21 +2439,21 @@ local function analyze_next_chars_two(c,font) local already_above_mark -- = false local already_below_mark -- = false local already_post_mark -- = false - while dependent_vowel[v] do - local vowels = twopart_mark[v] or { v } - for k, v in next, vowels do - if pre_mark[v] and not already_pre_mark then - already_pre_mark = true - elseif above_mark[v] and not already_above_mark then - already_above_mark = true - elseif below_mark[v] and not already_below_mark then - already_below_mark = true - elseif post_mark[v] and not already_post_mark then - already_post_mark = true - else - return c - end - end + while dependent_vowel[v] do + local vowels = twopart_mark[v] or { v } + for k, v in next, vowels do + if pre_mark[v] and not already_pre_mark then + already_pre_mark = true + elseif above_mark[v] and not already_above_mark then + already_above_mark = true + elseif below_mark[v] and not already_below_mark then + already_below_mark = true + elseif post_mark[v] and not already_post_mark then + already_post_mark = true + else + return c + end + end c = n n = getnext(c) if not n then @@ -2731,15 +2730,15 @@ local function method_one(head,font,attr) while current do local char = ischar(current,font) if char then - if n == 0 and not getstate(current) then - setstate(current,s_init) - end - n = n + 1 - else - n = 0 - end - current = getnext(current) - end + if n == 0 and not getstate(current) then + setstate(current,s_init) + end + n = n + 1 + else + n = 0 + end + current = getnext(current) + end return head, done end @@ -2841,15 +2840,15 @@ local function method_two(head,font,attr) while current do local char = ischar(current,font) if char then - if n == 0 and not getstate(current) then -- state can also be init - setstate(current,s_init) - end - n = n + 1 - else - n = 0 - end - current = getnext(current) - end + if n == 0 and not getstate(current) then -- state can also be init + setstate(current,s_init) + end + n = n + 1 + else + n = 0 + end + current = getnext(current) + end return head, done end diff --git a/tex/context/base/mkiv/font-otc.lua b/tex/context/base/mkiv/font-otc.lua index 2643d022a..2c955dbce 100644 --- a/tex/context/base/mkiv/font-otc.lua +++ b/tex/context/base/mkiv/font-otc.lua @@ -102,8 +102,9 @@ local function validspecification(specification,name) specification = { dataset = dataset } else dataset = { { data = specification.data } } - specification.data = nil - specification.dataset = dataset + specification.data = nil + specification.coverage = dataset + specification.dataset = dataset end local first = dataset[1] if first then @@ -232,6 +233,7 @@ local function addfeature(data,feature,specifications) local unicode = tounicode(code) local description = descriptions[unicode] if not nocheck and not description then + -- todo: trace ! skip = skip + 1 else if type(replacement) == "table" then @@ -436,7 +438,30 @@ local function addfeature(data,feature,specifications) local prepare_single = prepare_pair -- we could have a better test on the spec - local function prepare_chain(list,featuretype,sublookups) + local function hassteps(lookups) + if lookups then + for i=1,#lookups do + local l = lookups[i] + if l then + for j=1,#l do + local l = l[j] + if l then + local n = l.nofsteps + if not n then + -- gsub_remove + return true + elseif n > 0 then + return true + end + end + end + end + end + end + return false + end + + local function prepare_chain(list,featuretype,sublookups,nocheck) -- todo: coveractions local rules = list.rules local coverage = { } @@ -473,6 +498,7 @@ local function addfeature(data,feature,specifications) local lookups = rule.lookups or false local subtype = nil if lookups and sublookups then + local l = { } for k, v in sortedhash(lookups) do local t = type(v) if t == "table" then @@ -483,58 +509,66 @@ local function addfeature(data,feature,specifications) v[i] = { vi } end end + l[k] = v elseif t == "number" then local lookup = sublookups[v] if lookup then - lookups[k] = { lookup } + l[k] = { lookup } if not subtype then subtype = lookup.type end elseif v == 0 then - lookups[k] = { { type = "gsub_remove" } } + l[k] = { { type = "gsub_remove", nosteps = true } } else - lookups[k] = false -- { false } -- new + l[k] = false -- { false } -- new end else - lookups[k] = false -- { false } -- new + l[k] = false -- { false } -- new end end + if nocheck then + -- fragile + rule.lookups = l --no, because checking can spoil it + end + lookups = l end if nofsequences > 0 then -- we merge coverage into one -- we copy as we can have different fonts - local hashed = { } - for i=1,nofsequences do - local t = { } - local s = sequence[i] - for i=1,#s do - local u = tounicode(s[i]) - if u then - t[u] = true + if hassteps(lookups) then + local hashed = { } + for i=1,nofsequences do + local t = { } + local s = sequence[i] + for i=1,#s do + local u = tounicode(s[i]) + if u then + t[u] = true + end end + hashed[i] = t end - hashed[i] = t - end - sequence = hashed - -- now we create the rule - rulesize = rulesize + 1 - rulehash[rulesize] = { - nofrules, -- 1 - lookuptype, -- 2 - sequence, -- 3 - start, -- 4 - stop, -- 5 - lookups, -- 6 (6/7 also signal of what to do) - replacements, -- 7 - subtype, -- 8 - } --- for unic in next, sequence[start] do - for unic in sortedhash(sequence[start]) do - local cu = coverage[unic] - if not cu then - coverage[unic] = rulehash -- can now be done cleaner i think + sequence = hashed + rulesize = rulesize + 1 + rulehash[rulesize] = { + nofrules, -- 1 + lookuptype, -- 2 + sequence, -- 3 + start, -- 4 + stop, -- 5 + lookups, -- 6 (6/7 also signal of what to do) + replacements, -- 7 + subtype, -- 8 + } + for unic in sortedhash(sequence[start]) do + local cu = coverage[unic] + if not cu then + coverage[unic] = rulehash -- can now be done cleaner i think + end end + sequence.n = nofsequences + else + -- report_otf("no steps for %a",lookuptype) -- e.g. in primes feature end - sequence.n = nofsequences end end rulehash.n = rulesize @@ -626,133 +660,164 @@ local function addfeature(data,feature,specifications) end local askedfeatures = specification.features or everywhere local askedsteps = specification.steps or specification.subtables or { specification.data } or { } - local featuretype = normalized[specification.type or "substitution"] or "substitution" + local featuretype = specification.type or "substitution" + local featureaction = false local featureflags = specification.flags or noflags local nocheck = specification.nocheck + local mapping = specification.mapping local featureorder = specification.order or { feature } local featurechain = (featuretype == "chainsubstitution" or featuretype == "chainposition") and 1 or 0 local nofsteps = 0 local steps = { } local sublookups = specification.lookups local category = nil + local steptype = nil + local sequence = nil + -- + if fonts.handlers.otf.handlers[featuretype] then + featureaction = true -- function based + else + featuretype = normalized[specification.type or "substitution"] or "substitution" + end -- checkflags(specification,resources) -- - if sublookups then - local s = { } - for i=1,#sublookups do - local specification = sublookups[i] - local askedsteps = specification.steps or specification.subtables or { specification.data } or { } - local featuretype = normalized[specification.type or "substitution"] or "substitution" - local featureflags = specification.flags or noflags - local nofsteps = 0 - local steps = { } - for i=1,#askedsteps do - local list = askedsteps[i] - local coverage = nil - local format = nil - if featuretype == "substitution" then - coverage = prepare_substitution(list,featuretype,nocheck) - elseif featuretype == "ligature" then - coverage = prepare_ligature(list,featuretype,nocheck) - elseif featuretype == "alternate" then - coverage = prepare_alternate(list,featuretype,nocheck) - elseif featuretype == "multiple" then - coverage = prepare_multiple(list,featuretype,nocheck) - elseif featuretype == "kern" or featuretype == "move" then - format = featuretype - coverage = prepare_kern(list,featuretype) - elseif featuretype == "pair" then - format = "pair" - coverage = prepare_pair(list,featuretype) - elseif featuretype == "single" then - format = "single" - coverage = prepare_single(list,featuretype) - end - if coverage and next(coverage) then - nofsteps = nofsteps + 1 - steps[nofsteps] = register(coverage,featuretype,format,feature,nofsteps,descriptions,resources) + for k, v in next, askedfeatures do + if v[1] then + askedfeatures[k] = tohash(v) + end + end + -- + if featureflags[1] then featureflags[1] = "mark" end + if featureflags[2] then featureflags[2] = "ligature" end + if featureflags[3] then featureflags[3] = "base" end + -- + if featureaction then + + category = "gsub" + sequence = { + features = { [feature] = askedfeatures }, + flags = featureflags, + name = feature, -- redundant + order = featureorder, + type = featuretype, + -- steps = { }, + nofsteps = 0, -- just in case we test for that + } + + else + + if sublookups then + local s = { } + for i=1,#sublookups do + local specification = sublookups[i] + local askedsteps = specification.steps or specification.subtables or { specification.data } or { } + local featuretype = normalized[specification.type or "substitution"] or "substitution" + local featureflags = specification.flags or noflags + local nofsteps = 0 + local steps = { } + for i=1,#askedsteps do + local list = askedsteps[i] + local coverage = nil + local format = nil + if featuretype == "substitution" then + coverage = prepare_substitution(list,featuretype,nocheck) + elseif featuretype == "ligature" then + coverage = prepare_ligature(list,featuretype,nocheck) + elseif featuretype == "alternate" then + coverage = prepare_alternate(list,featuretype,nocheck) + elseif featuretype == "multiple" then + coverage = prepare_multiple(list,featuretype,nocheck) + elseif featuretype == "kern" or featuretype == "move" then + format = featuretype + coverage = prepare_kern(list,featuretype) + elseif featuretype == "pair" then + format = "pair" + coverage = prepare_pair(list,featuretype) + elseif featuretype == "single" then + format = "single" + coverage = prepare_single(list,featuretype) + end + if coverage and next(coverage) then + nofsteps = nofsteps + 1 + steps[nofsteps] = register(coverage,featuretype,format,feature,nofsteps,descriptions,resources) + end end + -- + checkmerge(specification) + checksteps(specification) + -- + s[i] = { + [stepkey] = steps, + nofsteps = nofsteps, + flags = featureflags, + type = types[featuretype], + } + end + sublookups = s + end + + for i=1,#askedsteps do + local list = askedsteps[i] + local coverage = nil + local format = nil + if featuretype == "substitution" then + -- see font-imp-tweaks: we directly pass a mapping so no checks done + category = "gsub" + coverage = (mapping and list) or prepare_substitution(list,featuretype,nocheck) + elseif featuretype == "ligature" then + category = "gsub" + coverage = prepare_ligature(list,featuretype,nocheck) + elseif featuretype == "alternate" then + category = "gsub" + coverage = prepare_alternate(list,featuretype,nocheck) + elseif featuretype == "multiple" then + category = "gsub" + coverage = prepare_multiple(list,featuretype,nocheck) + elseif featuretype == "kern" or featuretype == "move" then + category = "gpos" + format = featuretype + coverage = prepare_kern(list,featuretype) + elseif featuretype == "pair" then + category = "gpos" + format = "pair" + coverage = prepare_pair(list,featuretype) + elseif featuretype == "single" then + category = "gpos" + format = "single" + coverage = prepare_single(list,featuretype) + elseif featuretype == "chainsubstitution" then + category = "gsub" + coverage = prepare_chain(list,featuretype,sublookups,nocheck) + elseif featuretype == "chainposition" then + category = "gpos" + coverage = prepare_chain(list,featuretype,sublookups,nocheck) + else + report_otf("not registering feature %a, unknown category",feature) + return end - -- - checkmerge(specification) - checksteps(specification) - -- - s[i] = { + if coverage and next(coverage) then + nofsteps = nofsteps + 1 + steps[nofsteps] = register(coverage,featuretype,format,feature,nofsteps,descriptions,resources) + end + end + + if nofsteps > 0 then + sequence = { + chain = featurechain, + features = { [feature] = askedfeatures }, + flags = featureflags, + name = feature, -- redundant + order = featureorder, [stepkey] = steps, nofsteps = nofsteps, - flags = featureflags, type = types[featuretype], } end - sublookups = s end - for i=1,#askedsteps do - local list = askedsteps[i] - local coverage = nil - local format = nil - if featuretype == "substitution" then - category = "gsub" - coverage = prepare_substitution(list,featuretype,nocheck) - elseif featuretype == "ligature" then - category = "gsub" - coverage = prepare_ligature(list,featuretype,nocheck) - elseif featuretype == "alternate" then - category = "gsub" - coverage = prepare_alternate(list,featuretype,nocheck) - elseif featuretype == "multiple" then - category = "gsub" - coverage = prepare_multiple(list,featuretype,nocheck) - elseif featuretype == "kern" or featuretype == "move" then - category = "gpos" - format = featuretype - coverage = prepare_kern(list,featuretype) - elseif featuretype == "pair" then - category = "gpos" - format = "pair" - coverage = prepare_pair(list,featuretype) - elseif featuretype == "single" then - category = "gpos" - format = "single" - coverage = prepare_single(list,featuretype) - elseif featuretype == "chainsubstitution" then - category = "gsub" - coverage = prepare_chain(list,featuretype,sublookups) - elseif featuretype == "chainposition" then - category = "gpos" - coverage = prepare_chain(list,featuretype,sublookups) - else - report_otf("not registering feature %a, unknown category",feature) - return - end - if coverage and next(coverage) then - nofsteps = nofsteps + 1 - steps[nofsteps] = register(coverage,featuretype,format,feature,nofsteps,descriptions,resources) - end - end - if nofsteps > 0 then + + if sequence then -- script = { lang1, lang2, lang3 } or script = { lang1 = true, ... } - for k, v in next, askedfeatures do - if v[1] then - askedfeatures[k] = tohash(v) - end - end - -- - if featureflags[1] then featureflags[1] = "mark" end - if featureflags[2] then featureflags[2] = "ligature" end - if featureflags[3] then featureflags[3] = "base" end - local steptype = types[featuretype] - local sequence = { - chain = featurechain, - features = { [feature] = askedfeatures }, - flags = featureflags, - name = feature, -- redundant - order = featureorder, - [stepkey] = steps, - nofsteps = nofsteps, - type = steptype, - } - -- checkflags(sequence,resources) checkmerge(sequence) checksteps(sequence) @@ -782,11 +847,13 @@ local function addfeature(data,feature,specifications) end end end + end end if trace_loading then report_otf("registering feature %a, affected glyphs %a, skipped glyphs %a",feature,done,skip) end + end otf.enhancers.addfeature = addfeature diff --git a/tex/context/base/mkiv/font-otl.lua b/tex/context/base/mkiv/font-otl.lua index 6b564e4c1..eadf05890 100644 --- a/tex/context/base/mkiv/font-otl.lua +++ b/tex/context/base/mkiv/font-otl.lua @@ -314,7 +314,7 @@ local function copytotfm(data,cache_id) local properties = derivetable(data.properties) local descriptions = derivetable(data.descriptions) local goodies = derivetable(data.goodies) - local characters = { } + local characters = { } -- newtable if we knwo how many local parameters = { } local mathparameters = { } -- diff --git a/tex/context/base/mkiv/font-otr.lua b/tex/context/base/mkiv/font-otr.lua index 4b154b256..2f8934508 100644 --- a/tex/context/base/mkiv/font-otr.lua +++ b/tex/context/base/mkiv/font-otr.lua @@ -1250,7 +1250,7 @@ readers.post = function(f,fontdata,specification) local version = readulong(f) fontdata.postscript = { version = version, - italicangle = round(1000*readfixed(f))/1000, + italicangle = readfixed(f), underlineposition = readfword(f), underlinethickness = readfword(f), monospaced = readulong(f), diff --git a/tex/context/base/mkiv/grph-img.lua b/tex/context/base/mkiv/grph-img.lua index 0dc5efa70..a982965ff 100644 --- a/tex/context/base/mkiv/grph-img.lua +++ b/tex/context/base/mkiv/grph-img.lua @@ -16,7 +16,7 @@ local round = math.round local concat = table.concat local suffixonly = file.suffix -local newreader = io.newreader +local newreader = io.newreader -- needs checking 0/1 based local setmetatableindex = table.setmetatableindex local setmetatablecall = table.setmetatablecall diff --git a/tex/context/base/mkiv/l-gzip.lua b/tex/context/base/mkiv/l-gzip.lua index f141b5ebb..aadb781da 100644 --- a/tex/context/base/mkiv/l-gzip.lua +++ b/tex/context/base/mkiv/l-gzip.lua @@ -5,176 +5,4 @@ if not modules then modules = { } end modules ['l-gzip'] = { license = "see context related readme files" } --- We only have a few official methods here: --- --- local decompressed = gzip.load (filename) --- local resultsize = gzip.save (filename,compresslevel) --- local compressed = gzip.compress (str,compresslevel) --- local decompressed = gzip.decompress (str) --- local iscompressed = gzip.compressed (str) --- local suffix, okay = gzip.suffix (filename) --- --- In LuaMetaTeX we have only xzip which implements a very few methods: --- --- compress (str,level,method,window,memory,strategy) --- decompress (str,window) --- adler32 (str,checksum) --- crc32 (str,checksum) --- --- Special window values are: --- --- flate : - 15 --- zlib : 15 --- gzip : 15 | 16 --- auto : 15 | 32 - -gzip = gzip or { } -- so in luatex we keep the old ones too - -if not zlib then - zlib = xzip -- in luametatex we shadow the old one -elseif not xzip then - xzip = zlib -end - -if zlib then - - local suffix = file.suffix - local suffixes = file.suffixes - local find = string.find - local openfile = io.open - - local gzipwindow = 15 + 16 -- +16: gzip, +32: gzip|zlib - local gziplevel = 3 - local identifier = "^\x1F\x8B\x08" - - local compress = zlib.compress - local decompress = zlib.decompress - - function gzip.load(filename) - local f = openfile(filename,"rb") - if not f then - -- invalid file - else - local data = f:read("*all") - f:close() - if data and data ~= "" then - if suffix(filename) == "gz" then - data = decompress(data,gzipwindow) - end - return data - end - end - end - - function gzip.save(filename,data,level) - if suffix(filename) ~= "gz" then - filename = filename .. ".gz" - end - local f = openfile(filename,"wb") - if f then - data = compress(data or "",level or gziplevel,nil,gzipwindow) - f:write(data) - f:close() - return #data - end - end - - function gzip.suffix(filename) - local suffix, extra = suffixes(filename) - local gzipped = extra == "gz" - return suffix, gzipped - end - - function gzip.compressed(s) - return s and find(s,identifier) - end - - function gzip.compress(s,level) - if s and not find(s,identifier) then -- the find check might go away - if not level then - level = gziplevel - elseif level <= 0 then - return s - elseif level > 9 then - level = 9 - end - return compress(s,level or gziplevel,nil,gzipwindow) or s - end - end - - function gzip.decompress(s) - if s and find(s,identifier) then - return decompress(s,gzipwindow) - else - return s - end - end - -end - --- In luametatex we can use this one but it doesn't look like there wil be stream --- support so for now we still use zlib (the performance difference is not that --- spectacular in our usage. - --- if flate then --- --- local type = type --- local find = string.find --- --- local compress = flate.gz_compress --- local decompress = flate.gz_decompress --- --- local absmax = 128*1024*1024 --- local initial = 64*1024 --- local identifier = "^\x1F\x8B\x08" --- --- function gzip.compressed(s) --- return s and find(s,identifier) --- end --- --- function gzip.compress(s,level) --- if s and not find(s,identifier) then -- the find check might go away --- if not level then --- level = 3 --- elseif level <= 0 then --- return s --- elseif level > 9 then --- level = 9 --- end --- return compress(s,level) or s --- end --- end --- --- function gzip.decompress(s,size,iterate) --- if s and find(s,identifier) then --- if type(size) ~= "number" then --- size = initial --- end --- if size > absmax then --- size = absmax --- end --- if type(iterate) == "number" then --- max = size * iterate --- elseif iterate == nil or iterate == true then --- iterate = true --- max = absmax --- end --- if max > absmax then --- max = absmax --- end --- while true do --- local d = decompress(s,size) --- if d then --- return d --- end --- size = 2 * size --- if not iterate or size > max then --- return false --- end --- end --- else --- return s --- end --- end --- --- end +-- now in util-zip diff --git a/tex/context/base/mkiv/l-lpeg.lua b/tex/context/base/mkiv/l-lpeg.lua index 50306e4ab..77e5cf12d 100644 --- a/tex/context/base/mkiv/l-lpeg.lua +++ b/tex/context/base/mkiv/l-lpeg.lua @@ -665,12 +665,12 @@ end -- lpeg.print(lpeg.P("a","b","c")) -- lpeg.print(lpeg.S("a","b","c")) --- print(lpeg.count("äáàa",lpeg.P("á") + lpeg.P("à"))) --- print(lpeg.count("äáàa",lpeg.UP("áà"))) --- print(lpeg.count("äáàa",lpeg.US("àá"))) --- print(lpeg.count("äáàa",lpeg.UR("aá"))) --- print(lpeg.count("äáàa",lpeg.UR("àá"))) --- print(lpeg.count("äáàa",lpeg.UR(0x0000,0xFFFF))) +-- print(lpeg.counter("äáàa",lpeg.P("á") + lpeg.P("à"))) +-- print(lpeg.counter("äáàa",lpeg.UP("áà"))) +-- print(lpeg.counter("äáàa",lpeg.US("àá"))) +-- print(lpeg.counter("äáàa",lpeg.UR("aá"))) +-- print(lpeg.counter("äáàa",lpeg.UR("àá"))) +-- print(lpeg.counter("äáàa",lpeg.UR(0x0000,0xFFFF))) function lpeg.is_lpeg(p) return p and lpegtype(p) == "pattern" diff --git a/tex/context/base/mkiv/l-os.lua b/tex/context/base/mkiv/l-os.lua index c7584ccce..06cc35a79 100644 --- a/tex/context/base/mkiv/l-os.lua +++ b/tex/context/base/mkiv/l-os.lua @@ -187,7 +187,7 @@ local execute = os.execute local iopopen = io.popen local function resultof(command) - local handle = iopopen(command,"r") -- already has flush + local handle = iopopen(command,"rb") -- already has flush, b is new ! if handle then local result = handle:read("*all") or "" handle:close() diff --git a/tex/context/base/mkiv/lang-ini.lua b/tex/context/base/mkiv/lang-ini.lua index c8b5ee158..e286233bc 100644 --- a/tex/context/base/mkiv/lang-ini.lua +++ b/tex/context/base/mkiv/lang-ini.lua @@ -158,11 +158,16 @@ local function sethjcodes(instance,loaded,what,factor) loaded.codehash = h end -- - local function setcode(l) - local u = uccodes[l] + local function setcode(code) + local l = lccodes[code] -- just in case we get a mixture + local u = uccodes[code] -- just in case we get a mixture local s = l + if type(s) ~= "number" then + l = code + s = code + end if hjcounts then - local c = hjcounts[l] + local c = hjcounts[s] if c then c = c.count if not c then @@ -183,14 +188,14 @@ local function sethjcodes(instance,loaded,what,factor) h[l] = s if u ~= l and type(u) == "number" then sethjcode(instance,u,s) - h[u] = lccodes[l] + h[u] = s end end -- local s = tex.savinghyphcodes tex.savinghyphcodes = 0 if type(c) == "table" then - for l in next, c do + for l in sortedhash(c) do setcode(utfbyte(l)) end else diff --git a/tex/context/base/mkiv/luat-cnf.lua b/tex/context/base/mkiv/luat-cnf.lua index 550fa5892..7bb70ce20 100644 --- a/tex/context/base/mkiv/luat-cnf.lua +++ b/tex/context/base/mkiv/luat-cnf.lua @@ -261,4 +261,4 @@ local function makestub() logs.newline() end -lua.registerfinalizer(makestub,"create stub file") +lua.registerinitexfinalizer(makestub,"create stub file") diff --git a/tex/context/base/mkiv/luat-cod.lua b/tex/context/base/mkiv/luat-cod.lua index 25c716eeb..6175302a3 100644 --- a/tex/context/base/mkiv/luat-cod.lua +++ b/tex/context/base/mkiv/luat-cod.lua @@ -90,28 +90,6 @@ function lua.registercode(filename,options) end end -local finalizers = { } - -function lua.registerfinalizer(f,comment) - comment = comment or "unknown" - if type(f) == "function" then - finalizers[#finalizers+1] = { action = f, comment = comment } - else - print(format("\nfatal error: invalid finalizer, action: %s\n",comment)) - os.exit() - end -end - -function lua.finalize(logger) - for i=1,#finalizers do - local finalizer = finalizers[i] - finalizer.action() - if logger then - logger("finalize action: %s",finalizer.comment) - end - end -end - -- A first start with environments. This will be overloaded later. environment = environment or { } @@ -168,6 +146,38 @@ environment.jitsupported = JITSUPPORTED environment.initex = INITEXMODE environment.initexmode = INITEXMODE +if INITEXMODE then + + local finalizers = { } + + function lua.registerinitexfinalizer(f,comment) + comment = comment or "unknown" + if type(f) == "function" then + finalizers[#finalizers+1] = { action = f, comment = comment } + else + print(format("\nfatal error: invalid finalizer, action: %s\n",comment)) + os.exit() + end + end + + function lua.finalizeinitex(logger) + for i=1,#finalizers do + local finalizer = finalizers[i] + finalizer.action() + if logger then + logger("finalize action: %s",finalizer.comment) + end + end + end + +else + + function lua.registerinitexfinalizer() end + function lua.finalizeinitex () end + +end + + if not environment.luafilechunk then function environment.luafilechunk(filename) diff --git a/tex/context/base/mkiv/luat-lib.mkiv b/tex/context/base/mkiv/luat-lib.mkiv index f6bab870b..2879ca62a 100644 --- a/tex/context/base/mkiv/luat-lib.mkiv +++ b/tex/context/base/mkiv/luat-lib.mkiv @@ -53,13 +53,14 @@ \registerctxluafile{data-res}{} \registerctxluafile{data-inp}{} \registerctxluafile{data-out}{} -\registerctxluafile{data-fil}{} % opener gets overloaded in data-tex +\registerctxluafile{data-fil}{autosuffix} % opener gets overloaded in data-tex \registerctxluafile{data-pre}{} % after data-res \registerctxluafile{data-bin}{} % before data-tex \registerctxluafile{data-tex}{} % after data-pre \registerctxluafile{data-vir}{} \registerctxluafile{data-zip}{} +%registerctxluafile{data-tar}{} %registerctxluafile{data-crl}{} \registerctxluafile{data-sch}{} \registerctxluafile{data-tre}{} diff --git a/tex/context/base/mkiv/luat-run.lua b/tex/context/base/mkiv/luat-run.lua index 874287ee1..c778ad094 100644 --- a/tex/context/base/mkiv/luat-run.lua +++ b/tex/context/base/mkiv/luat-run.lua @@ -106,7 +106,7 @@ local function pre_dump_actions() for i=1,#dumpactions do dumpactions[i]() end - lua.finalize(trace_lua_dump and report_lua or nil) + lua.finalizeinitex(trace_lua_dump and report_lua or nil) end local function wrapup_synctex() diff --git a/tex/context/base/mkiv/luat-sto.lua b/tex/context/base/mkiv/luat-sto.lua index feb546400..be5134b84 100644 --- a/tex/context/base/mkiv/luat-sto.lua +++ b/tex/context/base/mkiv/luat-sto.lua @@ -90,7 +90,7 @@ if environment.initex then storage.max = max end - lua.registerfinalizer(dump,"dump storage") + lua.registerinitexfinalizer(dump,"dump storage") end diff --git a/tex/context/base/mkiv/lxml-ini.lua b/tex/context/base/mkiv/lxml-ini.lua index 6524670fc..980a83f1a 100644 --- a/tex/context/base/mkiv/lxml-ini.lua +++ b/tex/context/base/mkiv/lxml-ini.lua @@ -205,7 +205,6 @@ if CONTEXTLMTXMODE > 0 then end } - implement { name = "ifxmlempty", public = true, diff --git a/tex/context/base/mkiv/lxml-tex.lua b/tex/context/base/mkiv/lxml-tex.lua index 148484f51..95fafafac 100644 --- a/tex/context/base/mkiv/lxml-tex.lua +++ b/tex/context/base/mkiv/lxml-tex.lua @@ -2085,11 +2085,11 @@ do local e = getid(id) if e then local at = e.at - if at and at[a] ~= "" then - return true - end + att = at and at[a] or "" + else + att = "" end - return false + return att == "" end function lxml.refatt(id,a) diff --git a/tex/context/base/mkiv/mult-low.lua b/tex/context/base/mkiv/mult-low.lua index 2b2173ae9..8132c6094 100644 --- a/tex/context/base/mkiv/mult-low.lua +++ b/tex/context/base/mkiv/mult-low.lua @@ -97,6 +97,12 @@ return { "mmodeifcode", "innerifcode", "voidifcode", "hboxifcode", "vboxifcode", "xifcode", "eofifcode", "trueifcode", "falseifcode", "caseifcode", "definedifcode", "csnameifcode", "fontcharifcode", -- + "overrulemathcontrolcode", "underrulemathcontrolcode", "radicalrulemathcontrolcode", "fractionrulemathcontrolcode", + "accentskewhalfmathcontrolcode", "accentskewapplymathcontrolcode", "accentitalickernmathcontrolcode", + "delimiteritalickernmathcontrolcode", "orditalickernmathcontrolcode", "charitalicwidthmathcontrolcode", + "charitalicnoreboxmathcontrolcode", "boxednoitalickernmathcontrolcode", "nostaircasekernmathcontrolcode", + "textitalickernmathcontrolcode", + -- "fontslantperpoint", "fontinterwordspace", "fontinterwordstretch", "fontinterwordshrink", "fontexheight", "fontemwidth", "fontextraspace", "slantperpoint", "mathexheight", "mathemwidth", @@ -177,6 +183,8 @@ return { "frozenflagcode", "tolerantflagcode", "protectedflagcode", "primitiveflagcode", "permanentflagcode", "noalignedflagcode", "immutableflagcode", "mutableflagcode", "globalflagcode", "overloadedflagcode", "immediateflagcode", "conditionalflagcode", "valueflagcode", "instanceflagcode", -- + "ordflattencode", "binflattencode", "relflattencode", "punctflattencode", "innerflattencode", + -- "prewordcode", "postwordcode", -- "continuewhenlmtxmode" @@ -563,6 +571,8 @@ return { -- "suggestedalias", -- + "showboxhere", + -- "newlocalcount", "newlocaldimen", "newlocalskip", "newlocalmuskip", "newlocaltoks", "newlocalbox", "newlocalwrite", "newlocalread", "setnewlocalcount", "setnewlocaldimen", "setnewlocalskip", "setnewlocalmuskip", "setnewlocaltoks", "setnewlocalbox", diff --git a/tex/context/base/mkiv/mult-prm.lua b/tex/context/base/mkiv/mult-prm.lua index 6338bff40..2cb38e8a3 100644 --- a/tex/context/base/mkiv/mult-prm.lua +++ b/tex/context/base/mkiv/mult-prm.lua @@ -32,14 +32,11 @@ return { "iffontchar", "interactionmode", "interlinepenalties", - "lastchkdim", - "lastchknum", "lastlinefit", "lastnodetype", "marks", "muexpr", "mutoglue", - "numericscale", "numexpr", "pagediscards", "parshapedimen", @@ -120,6 +117,10 @@ return { "Umathdelimiterovervariant", "Umathdelimiterundervariant", "Umathdenominatorvariant", + "Umathextrasubpreshift", + "Umathextrasubshift", + "Umathextrasuppreshift", + "Umathextrasupshift", "Umathfractiondelsize", "Umathfractiondenomdown", "Umathfractiondenomvgap", @@ -318,9 +319,11 @@ return { "explicithyphenpenalty", "firstvalidlanguage", "fontid", + "fontmathcontrol", "fontspecifiedsize", "formatname", "frozen", + "futurecsname", "futuredef", "futureexpand", "futureexpandis", @@ -396,6 +399,8 @@ return { "instance", "integerdef", "lastarguments", + "lastchkdim", + "lastchknum", "lastnamedcs", "lastnodesubtype", "leftmarginkern", @@ -423,11 +428,13 @@ return { "luatexbanner", "luatexrevision", "luatexversion", + "mathcontrolmode", "mathdelimitersmode", "mathdirection", "mathdisplayskipmode", "matheqnogapstep", "mathflattenmode", + "mathfontcontrol", "mathitalicsmode", "mathnolimitsmode", "mathpenaltiesmode", @@ -450,6 +457,7 @@ return { "normalizelinemode", "nospaces", "novrule", + "numericscale", "orelse", "orunless", "outputbox", @@ -492,6 +500,7 @@ return { "undent", "unletfrozen", "unletprotected", + "untraced", "vpack", "wordboundary", "wrapuppar", diff --git a/tex/context/base/mkiv/node-res.lua b/tex/context/base/mkiv/node-res.lua index 408f8ea47..5c669f9da 100644 --- a/tex/context/base/mkiv/node-res.lua +++ b/tex/context/base/mkiv/node-res.lua @@ -590,7 +590,7 @@ statistics.register("node memory usage", function() -- comes after cleanup ! end end) -lua.registerfinalizer(cleanup, "cleanup reserved nodes") +lua.registerinitexfinalizer(cleanup, "cleanup reserved nodes") -- experiment diff --git a/tex/context/base/mkiv/node-syn.lua b/tex/context/base/mkiv/node-syn.lua index 8b8b628dd..4014445b0 100644 --- a/tex/context/base/mkiv/node-syn.lua +++ b/tex/context/base/mkiv/node-syn.lua @@ -231,8 +231,8 @@ local blockedsuffixes = { -- lfg = true, } -local sttags = table.setmetatableindex(function(t,name) - name = collapsepath(name) +local sttags = table.setmetatableindex(function(t,fullname) + local name = collapsepath(fullname) if blockedsuffixes[suffixonly(name)] then -- Just so that I don't get the ones on my development tree. nofblocked = nofblocked + 1 @@ -248,6 +248,9 @@ local sttags = table.setmetatableindex(function(t,name) else noftags = noftags + 1 t[name] = noftags + if name ~= fullname then + t[fullname] = noftags + end stnums[noftags] = name return noftags end diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf Binary files differindex 2558e805e..4c0c46993 100644 --- a/tex/context/base/mkiv/status-files.pdf +++ b/tex/context/base/mkiv/status-files.pdf diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf Binary files differindex dcbc15681..ca29ed3a5 100644 --- a/tex/context/base/mkiv/status-lua.pdf +++ b/tex/context/base/mkiv/status-lua.pdf diff --git a/tex/context/base/mkiv/supp-box.lua b/tex/context/base/mkiv/supp-box.lua index 4b9322ba7..2e7ca5924 100644 --- a/tex/context/base/mkiv/supp-box.lua +++ b/tex/context/base/mkiv/supp-box.lua @@ -171,7 +171,7 @@ implement { arguments = "integer", actions = function(n) -- we just hyphenate (as we pass a hpack) .. a bit too much casting but ... - local l = languages.hyphenators.handler(tonode(checkedlist(n))) + local l = languages.hyphenators.handler(checkedlist(n)) report_hyphenation("show: %s",listtoutf(l,false,true)) end } diff --git a/tex/context/base/mkiv/util-fil.lua b/tex/context/base/mkiv/util-fil.lua index 183f7bea8..0b20264ec 100644 --- a/tex/context/base/mkiv/util-fil.lua +++ b/tex/context/base/mkiv/util-fil.lua @@ -203,23 +203,23 @@ function files.readinteger4le(f) end function files.readfixed2(f) - local a, b = byte(f:read(2),1,2) - if a >= 0x80 then - tonumber((a - 0x100) .. "." .. b) - else - tonumber(( a ) .. "." .. b) + local n1, n2 = byte(f:read(2),1,2) + if n1 >= 0x80 then + n1 = n1 - 0x100 end + return n1 + n2/0xFF end -- (real) (n>>16) + ((n&0xffff)/65536.0)) but no cast in lua (we could use unpack) function files.readfixed4(f) local a, b, c, d = byte(f:read(4),1,4) - if a >= 0x80 then - tonumber((0x100 * a + b - 0x10000) .. "." .. (0x100 * c + d)) - else - tonumber((0x100 * a + b ) .. "." .. (0x100 * c + d)) + local n1 = 0x100 * a + b + local n2 = 0x100 * c + d + if n1 >= 0x8000 then + n1 = n1 - 0x10000 end + return n1 + n2/0xFFFF end -- (real) ((n<<16)>>(16+14)) + ((n&0x3fff)/16384.0)) diff --git a/tex/context/base/mkiv/util-sac.lua b/tex/context/base/mkiv/util-sac.lua index 522b0bc08..796a620ba 100644 --- a/tex/context/base/mkiv/util-sac.lua +++ b/tex/context/base/mkiv/util-sac.lua @@ -262,12 +262,11 @@ function streams.readfixed2(f) local i = f[2] local j = i + 1 f[2] = j + 1 - local a, b = byte(f[1],i,j) - if a >= 0x80 then - return tonumber((a - 0x100) .. "." .. b) or 0 - else - return tonumber((a ) .. "." .. b) or 0 + local n1, n2 = byte(f[1],i,j) + if n1 >= 0x80 then + n1 = n1 - 0x100 end + return n1 + n2/0xFF end function streams.readfixed4(f) @@ -275,11 +274,12 @@ function streams.readfixed4(f) local j = i + 3 f[2] = j + 1 local a, b, c, d = byte(f[1],i,j) - if a >= 0x80 then - return tonumber((0x100 * a + b - 0x10000) .. "." .. (0x100 * c + d)) or 0 - else - return tonumber((0x100 * a + b ) .. "." .. (0x100 * c + d)) or 0 + local n1 = 0x100 * a + b + local n2 = 0x100 * c + d + if n1 >= 0x8000 then + n1 = n1 - 0x10000 end + return n1 + n2/0xFFFF end if bit32 then @@ -507,10 +507,10 @@ do function io.newreader(str,method) local f, m if method == "string" then - f = openstring(str) + f = openstring(str,true) m = streams elseif method == "stream" then - f = openstream(str) + f = openstream(str,true) m = streams else f = openfile(str,"rb") @@ -522,6 +522,7 @@ do __index = function(t,k) local r = m[k] if k == "close" then + -- maybe use __toclose if f then m.close(f) f = nil diff --git a/tex/context/base/mkiv/util-tar.lua b/tex/context/base/mkiv/util-tar.lua new file mode 100644 index 000000000..0368a7db5 --- /dev/null +++ b/tex/context/base/mkiv/util-tar.lua @@ -0,0 +1,359 @@ +if not modules then modules = { } end modules ['util-tar'] = { + version = 1.001, + comment = "companion to luat-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local type, tonumber = type, tonumber +local gsub, escapedpattern = string.gsub, string.escapedpattern +local nameonly, dirname, makedirs = file.nameonly, file.dirname, dir.makedirs +local savedata = io.savedata +local newreader = io.newreader + +local report = logs.reporter("tar") + +local types = { + ["0"] = "file", + ["\0"] = "regular", + ["1"] = "link", + ["2"] = "symbolic", -- reserved + ["3"] = "character", + ["4"] = "block", + ["5"] = "directory", + ["6"] = "fifo", + ["7"] = "continuation", -- reserved + ["x"] = "extended", -- header +} + +local function asstring(str) + return str and gsub(str,"[\0 ]+$","") or nil +end + +local function asnumber(str) + str = gsub(str,"\0$","") + return tonumber(str,8) +end + +local function opentar(whatever,filename) + local f = newreader(filename,whatever) + if f then + f.metadata = { + nofpaths = 0, + noffiles = 0, + noflinks = 0, + nofbytes = 0, + } + return f + end +end + +local function readheader(t) + -- checksum + local p = t:getposition() + local h = t:readbytetable(512) + t:setposition(p) + for i=149,156 do -- nasty, one less + h[i] = 0 + end + local c = 256 + for i=1,512 do + c = c + h[i] + end + -- + local header = { + name = asstring(t:readstring(100)), -- 0 + mode = asnumber(t:readstring( 8)), -- 100 -- when we write: 0775 octal + uid = asnumber(t:readstring( 8)), -- 108 + gid = asnumber(t:readstring( 8)), -- 116 + size = asnumber(t:readstring( 12)), -- 124 + mtime = asnumber(t:readstring( 12)), -- 136 + checksum = asnumber(t:readstring( 6)), -- 148 -- actually 6 with space and \0 + dummy = t:skip (2) , + typeflag = t:readstring( 1) , -- 156 + linkname = asstring(t:readstring(100)), -- 157 + -- magic = asstring(t:readstring( 6)), -- 257 -- ustar\0 + -- version = 2 -- 263 + -- uname = 32 -- 265 + -- gname = 32 -- 297 + -- devmajor = 8 -- 329 + -- devminor = 8 -- 337 + -- prefix = 155 -- 345 + padding = t:skip (255) , -- 500 + } + local typeflag = header.typeflag + if typeflag then + header.filetype = types[typeflag] + if c == header.checksum then + return header + end + end +end + +local readers = { + + directory = function(t,h) + local metadata = t.metadata + local filename = h.name + if metadata.verbose then + report("%8s %s","",filename) + end + metadata.nofpaths = metadata.nofpaths + 1 + return true + end, + + file = function(t,h) + local metadata = t.metadata + local filename = h.name + local filesize = h.size + local pathname = dirname(filename) + if metadata.verbose then + report("% 8i : %s",filesize,filename) + end + if makedirs(pathname) then + savedata(filename,t:readstring(filesize)) + else + t.skip(filesize) + end + local position = t:getposition() + local target = position + (512 - position % 512) % 512 + t:setposition(target) + metadata.noffiles = metadata.noffiles + 1 + metadata.nofbytes = metadata.nofbytes + filesize + return true + end, + + link = function(t,h) + local metadata = t.metadata + local filename = h.name + local linkname = h.linkname + if metadata.verbose then + report("%8s %s => %s","",linkname,filename) + end + metadata.noflinks = metadata.noflinks + 1 + return true + end, + +} + +local skippers = { + + directory = function(t,h) + return true + end, + + file = function(t,h) + local filesize = h.size + local fileoffset = t:getposition() + local position = filesize + fileoffset + local target = position + (512 - position % 512) % 512 + t:setposition(target) + return fileoffset + end, + + link = function(t,h) + return true + end, + +} + +local writers = { + -- nothing here (yet) +} + +local function saveheader(t,h) + local filetype = h.filetype + local reader = readers[filetype] + if reader then + return filetype, reader(t,h) + else + report("no reader for %s",filetype) + end +end + +local function skipheader(t,h) + local filetype = h.filetype + local skipper = skippers[filetype] + if skipper then + return filetype, skipper(t,h) + else + report("no skipper for %s",filetype) + end +end + +local function unpacktar(whatever,filename,verbose) + local t = opentar(whatever,filename) + if t then + local metadata = t.metadata + statistics.starttiming(metadata) + if verbose then + if whatever == "string" then + report("unpacking: %i bytes",#filename) + else + report("unpacking: %s",filename) + end + report("") + metadata.verbose = verbose + end + while true do + local h = readheader(t) + if not h then + break + else + local filetype, saved = saveheader(t,h) + if not saved then + break + end + end + end + statistics.stoptiming(metadata) + metadata.runtime = statistics.elapsed(metadata) + if verbose then + report("") + report("number of paths : %i",metadata.nofpaths) + report("number of files : %i",metadata.noffiles) + report("number of links : %i",metadata.noflinks) + report("number of bytes : %i",metadata.nofbytes) + report("") + report("runtime needed : %s",statistics.elapsedseconds(metadata)) + report("") + end + t.close() + return metadata + end +end + +local function listtar(whatever,filename,onlyfiles) + local t = opentar(whatever,filename) + if t then + local list, n = { }, 0 + while true do + local h = readheader(t) + if not h then + break + else + local filetype, offset = skipheader(t,h) + if not offset then + break + elseif filetype == "file" then + n = n + 1 ; list[n] = { filetype, h.name, h.size } + elseif filetype == "link" then + n = n + 1 ; list[n] = { filetype, h.name, h.linkfile } + elseif not onlyfiles then + n = n + 1 ; list[n] = { filetype, h.name } + end + end + end + t.close() + -- can be an option + table.sort(list,function(a,b) return a[2] < b[2] end) + return list + end +end + +local function hashtar(whatever,filename,strip) + local t = opentar(whatever,filename) + if t then + local list = { } + if strip then + strip = "^" .. escapedpattern(nameonly(nameonly(strip))) .. "/" + end + while true do + local h = readheader(t) + if not h then + break + else + local filetype, offset = skipheader(t,h) + if not offset then + break + else + local name = h.name + if strip then + name = gsub(name,strip,"") + end + if filetype == "file" then + list[name] = { offset, h.size } + elseif filetype == "link" then + list[name] = h.linkname + end + end + end + end + t.close() + return list + end +end + +-- weak table ? + +local function fetchtar(whatever,archive,filename,list) + if not list then + list = hashtar(whatever,archive) + end + if list then + local what = list[filename] + if type(what) == "string" then + what = list[what] -- a link + end + if what then + local t = opentar(whatever,archive) + if t then + t:setposition(what[1]) + return t:readstring(what[2]) + end + end + end +end + +local function packtar(whatever,filename,verbose) + report("packing will be implemented when we need it") +end + +local tar = { + files = { + unpack = function(...) return unpacktar("file", ...) end, + pack = function(...) return packtar ("file", ...) end, + list = function(...) return listtar ("file", ...) end, + hash = function(...) return hashtar ("file", ...) end, + fetch = function(...) return fetchtar ("file", ...) end, + }, + strings = { + unpack = function(...) return unpacktar("string",...) end, + pack = function(...) return packtar ("string",...) end, + list = function(...) return listtar ("string",...) end, + hash = function(...) return hashtar ("string",...) end, + fetch = function(...) return fetchtar ("string",...) end, + }, + streams = { + unpack = function(...) return unpacktar("stream",...) end, + pack = function(...) return packtar ("stream",...) end, + list = function(...) return listtar ("stream",...) end, + hash = function(...) return hashtar ("stream",...) end, + fetch = function(...) return fetchtar ("stream",...) end, + }, +} + +utilities.tar = tar + +-- tar.files .unpack("e:/luatex/luametatex-source.tar",true) +-- tar.streams.unpack("e:/luatex/luametatex-source.tar",true) +-- tar.strings.unpack(io.loaddata("e:/luatex/luametatex-source.tar"),true) + +-- inspect(tar.files .unpack("e:/luatex/luametatex-source.tar")) +-- inspect(tar.streams.unpack("e:/luatex/luametatex-source.tar")) +-- inspect(tar.strings.unpack(io.loaddata("e:/luatex/luametatex-source.tar"))) + +-- inspect(tar.files .list("e:/luatex/luametatex-source.tar",true)) +-- inspect(tar.streams.list("e:/luatex/luametatex-source.tar",true)) +-- inspect(tar.strings.list(io.loaddata("e:/luatex/luametatex-source.tar"),true)) + +-- local c = os.clock() +-- local l = tar.files.hash("e:/luatex/luametatex-source.tar") +-- for i=1,500 do +-- local s = tar.files.fetch("e:/luatex/luametatex-source.tar", "luametatex-source/source/tex/texbuildpage.c", l) +-- local s = tar.files.fetch( "e:/luatex/luametatex-source.tar","luametatex-source/source/lua/lmtlibrary.c", l) +-- end +-- print(os.clock()-c) + +return tar diff --git a/tex/context/base/mkiv/util-zip.lua b/tex/context/base/mkiv/util-zip.lua index e97f3a065..67c1a715f 100644 --- a/tex/context/base/mkiv/util-zip.lua +++ b/tex/context/base/mkiv/util-zip.lua @@ -21,6 +21,14 @@ local ioopen = io.open local loaddata, savedata = io.loaddata, io.savedata local filejoin, isdir, dirname, mkdirs = file.join, lfs.isdir, file.dirname, dir.mkdirs +gzip = gzip or { } -- so in luatex we keep the old ones too + +if not zlib then + zlib = xzip -- in luametatex we shadow the old one +elseif not xzip then + xzip = zlib +end + local files = utilities.files local openfile = files.open local closefile = files.close @@ -497,48 +505,157 @@ if xzip then -- flate then do end -zipfiles.gunzipfile = gzip.load +if not gzip.compress then + + -- todo: compress/decompress that work with offset in string + + -- We only have a few official methods here: + -- + -- local decompressed = gzip.load (filename) + -- local resultsize = gzip.save (filename,compresslevel) + -- local compressed = gzip.compress (str,compresslevel) + -- local decompressed = gzip.decompress (str) + -- local iscompressed = gzip.compressed (str) + -- local suffix, okay = gzip.suffix (filename) + -- + -- In LuaMetaTeX we have only xzip which implements a very few methods: + -- + -- compress (str,level,method,window,memory,strategy) + -- decompress (str,window) + -- adler32 (str,checksum) + -- crc32 (str,checksum) + -- + -- Special window values are: + -- + -- flate : - 15 + -- zlib : 15 + -- gzip : - 15 + + local suffix = file.suffix + local suffixes = file.suffixes + local find = string.find + local concat = table.concat + local openfile = io.open + + local gzipwindow = -15 -- miniz needs this + local gziplevel = 3 + local identifier = "\x1F\x8B" + local pattern = "^\x1F\x8B\x08" + + local compress = zlib.compress + local decompress = zlib.decompress + local crc32 = zlib.crc32 + + local streams = utilities.streams + local openstream = streams.openstring + local closestream = streams.close + local getposition = streams.getposition + local readbyte = streams.readbyte + local readcardinal4 = streams.readcardinal4le + local readcardinal2 = streams.readcardinal2le + local readstring = streams.readstring + local readcstring = streams.readcstring + local skipbytes = streams.skip + + local tocardinal1 = streams.tocardinal1 + local tocardinal4 = streams.tocardinal4le + + local function getdecompressed(str) + local s = openstream(str) + local identifier = readstring(s,2) + local method = readbyte(s,1) + local flags = readbyte(s,1) + local timestamp = readcardinal4(s) + local compression = readbyte(s,1) + local operating = readbyte(s,1) + local isjusttext = (flags & 0x01 ~= 0) and true or false + local extrasize = (flags & 0x04 ~= 0) and readcardinal2(s) or 0 + local filename = (flags & 0x08 ~= 0) and readcstring(s) or "" + local comment = (flags & 0x10 ~= 0) and readcstring(s) or "" + local checksum = (flags & 0x02 ~= 0) and readcardinal2(s) or 0 + local compressed = readstring(s,#str) + local data = decompress(compressed,gzipwindow) -- pass offset + return data + end --- if flate then --- --- local streams = utilities.streams --- local openfile = streams.open --- local closestream = streams.close --- local setposition = streams.setposition --- local getsize = streams.size --- local readcardinal4 = streams.readcardinal4le --- local getstring = streams.getstring --- local decompress = flate.gz_decompress --- --- -- id1=1 id2=1 method=1 flags=1 mtime=4(le) extra=1 os=1 --- -- flags:8 comment=...<nul> flags:4 name=...<nul> flags:2 extra=...<nul> flags:1 crc=2 --- -- data:? --- -- crc=4 size=4 --- --- function zipfiles.gunzipfile(filename) --- local strm = openfile(filename) --- if strm then --- setposition(strm,getsize(strm) - 4 + 1) --- local size = readcardinal4(strm) --- local data = decompress(getstring(strm),size) --- closestream(strm) --- return data --- end --- end --- --- elseif gzip then --- --- local openfile = gzip.open --- --- function zipfiles.gunzipfile(filename) --- local g = openfile(filename,"rb") --- if g then --- local d = g:read("*a") --- d:close() --- return d --- end --- end --- --- end + local function putcompressed(str,level,originalname) + return concat { + identifier, -- 2 identifier + tocardinal1(0x08), -- 1 method + tocardinal1(0x08), -- 1 flags + tocardinal4(os.time()), -- 4 mtime + tocardinal1(0x02), -- 1 compression (2 or 4) + tocardinal1(0xFF), -- 1 operating + (originalname or "unknownname") .. "\0", + compress(str,level,nil,gzipwindow), + tocardinal4(crc32(str)), -- 4 + tocardinal4(#str), -- 4 + } + end + + function gzip.load(filename) + local f = openfile(filename,"rb") + if not f then + -- invalid file + else + local data = f:read("*all") + f:close() + if data and data ~= "" then + if suffix(filename) == "gz" then + data = getdecompressed(data) + end + return data + end + end + end + + function gzip.save(filename,data,level,originalname) + if suffix(filename) ~= "gz" then + filename = filename .. ".gz" + end + local f = openfile(filename,"wb") + if f then + data = putcompressed(data or "",level or gziplevel,originalname) + f:write(data) + f:close() + return #data + end + end + + function gzip.suffix(filename) + local suffix, extra = suffixes(filename) + local gzipped = extra == "gz" + return suffix, gzipped + end + + function gzip.compressed(s) + return s and find(s,identifier) + end + + function gzip.compress(s,level) + if s and not find(s,identifier) then -- the find check might go away + if not level then + level = gziplevel + elseif level <= 0 then + return s + elseif level > 9 then + level = 9 + end + return putcompressed(s,level or gziplevel) or s + end + end + + function gzip.decompress(s) + if s and find(s,identifier) then + return getdecompressed(s) + else + return s + end + end + + +end + +zipfiles.gunzipfile = gzip.load return zipfiles |