diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/context/lua/mtx-chars.lua | 5 | ||||
-rw-r--r-- | scripts/context/lua/mtx-colors.lua | 51 | ||||
-rw-r--r-- | scripts/context/lua/mtx-context.lua | 5 | ||||
-rw-r--r-- | scripts/context/lua/mtx-fonts.lua | 7 | ||||
-rw-r--r-- | scripts/context/lua/mtx-interface.lua | 14 | ||||
-rw-r--r-- | scripts/context/lua/mtx-patterns.lua | 593 | ||||
-rw-r--r-- | scripts/context/lua/mtx-server-ctx-fonttest.lua | 2 | ||||
-rw-r--r-- | scripts/context/lua/mtx-server.lua | 2 | ||||
-rw-r--r-- | scripts/context/lua/mtxrun.lua | 311 | ||||
-rw-r--r-- | scripts/context/stubs/mswin/mtxrun.lua | 311 | ||||
-rwxr-xr-x | scripts/context/stubs/unix/mtxrun | 311 |
11 files changed, 1183 insertions, 429 deletions
diff --git a/scripts/context/lua/mtx-chars.lua b/scripts/context/lua/mtx-chars.lua index 6acacfbd2..ea4a6061f 100644 --- a/scripts/context/lua/mtx-chars.lua +++ b/scripts/context/lua/mtx-chars.lua @@ -143,6 +143,11 @@ local banner_utf_patch = [[ \setXTXcharcodes "201C "201C "201C \setXTXcharcodes "201D "201D "201D + +% patch needed for french + +\setXTXcharcodes "2019 "2019 "2019 + ]] local banner_utf_names = [[ diff --git a/scripts/context/lua/mtx-colors.lua b/scripts/context/lua/mtx-colors.lua new file mode 100644 index 000000000..a99fd7257 --- /dev/null +++ b/scripts/context/lua/mtx-colors.lua @@ -0,0 +1,51 @@ +if not modules then modules = { } end modules ['mtx-colors'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- todo: fc-cache -v en check dirs, or better is: fc-cat -v | grep Directory + +if not fontloader then fontloader = fontforge end + +dofile(resolvers.find_file("colo-icc.lua","tex")) + +scripts = scripts or { } +scripts.colors = scripts.colors or { } + +function scripts.colors.table() + local files = environment.files + if #files > 0 then + for i=1,#files do + local profile, okay, message = colors.iccprofile(files[i]) + if not okay then + logs.simple(message) + else + logs.simple(table.serialize(profile,"profile")) + end + end + else + logs.simple("no file(s) given" ) + end +end + +logs.extendbanner("ConTeXt Color Management 0.1") + +messages.help = [[ +--table show icc table + +example: + +mtxrun --script color --table somename +]] + +--~ local track = environment.argument("track") +--~ if track then trackers.enable(track) end + +if environment.argument("table") then + scripts.colors.table() +else + logs.help(messages.help) +end diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua index 785539754..66b8a6311 100644 --- a/scripts/context/lua/mtx-context.lua +++ b/scripts/context/lua/mtx-context.lua @@ -439,14 +439,13 @@ function scripts.context.multipass.makeoptionfile(jobname,ctxdata,kindofrun,curr f:write(format:format(...),"\n") end -- + -- This might change ... we can just pass the relevant flags directly. + -- setalways("%% runtime options files (command line driven)") -- setalways("\\unprotect") -- setalways("%% feedback and basic job control") - if type(environment.argument("track")) == "string" then - setvalue ("track" , "\\enabletrackers[%s]") - end if type(environment.argument("trackers")) == "string" then setvalue ("trackers" , "\\enabletrackers[%s]") end diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua index b8bbdde5b..9e370b2d5 100644 --- a/scripts/context/lua/mtx-fonts.lua +++ b/scripts/context/lua/mtx-fonts.lua @@ -194,10 +194,9 @@ local function list_specifications(t,info) fontweight(entry.fontweight), } end - table.formatcolumns(s) + aux.formatcolumns(s) for k=1,#s do - local v = s[k] - texio.write_nl(v) + texio.write_nl(s[k]) end end end @@ -222,7 +221,7 @@ local function list_matches(t,info) subfont(entry.subfont) } end - table.formatcolumns(s) + aux.formatcolumns(s) for k=1,#s do texio.write_nl(s[k]) end diff --git a/scripts/context/lua/mtx-interface.lua b/scripts/context/lua/mtx-interface.lua index 34ecffab0..12a6d0e29 100644 --- a/scripts/context/lua/mtx-interface.lua +++ b/scripts/context/lua/mtx-interface.lua @@ -161,7 +161,7 @@ function scripts.interface.context() local v = t[key] local value = v[language] or v["en"] if not value then - logs.simple(format("warning, no value for key '%s' for language '%s'",key,language)) + logs.simple("warning, no value for key '%s' for language '%s'",key,language) else local value = t[key][language] or t[key].en texresult[#texresult+1] = format("\\setinterface%s{%s}{%s}",tag,key,value) @@ -199,9 +199,9 @@ function scripts.interface.context() local texfilename = format("mult-%s.tex",language) local xmlfilename = format("keys-%s.xml",language) io.savedata(texfilename,table.concat(texresult,"\n")) - logs.simple(format("saving interface definitions '%s'",texfilename)) + logs.simple("saving interface definitions '%s'",texfilename) io.savedata(xmlfilename,table.concat(xmlresult,"\n")) - logs.simple(format("saving interface translations '%s'",xmlfilename)) + logs.simple("saving interface translations '%s'",xmlfilename) if language ~= "en" and xmldata ~= "" then local newdata = xmldata:gsub("(<cd:interface.*language=.)en(.)","%1"..language.."%2",1) newdata = replace(newdata, 'cd:string', 'value', interface.commands, interface.elements, language) @@ -212,7 +212,7 @@ function scripts.interface.context() newdata = replace(newdata, 'cd:inherit', 'name', interface.commands, interface.elements, language) local xmlfilename = format("cont-%s.xml",language) io.savedata(xmlfilename,newdata) - logs.simple(format("saving interface specification '%s'",xmlfilename)) + logs.simple("saving interface specification '%s'",xmlfilename) end end end @@ -223,6 +223,8 @@ function scripts.interface.messages() local filename = resolvers.find_file(environment.files[1] or "mult-mes.lua") or "" if filename ~= "" then local messages = dofile(filename) + logs.simple("messages for * loaded from '%s'",filename) + logs.simple() for i=1,#messageinterfaces do local interface = messageinterfaces[i] local texresult = { } @@ -237,7 +239,9 @@ function scripts.interface.messages() end end texresult[#texresult+1] = format("%%\n\\endinput") - io.savedata(format("mult-m%s.tex",interface),table.concat(texresult,"\n")) + local interfacefile = format("mult-m%s.tex",interface) + io.savedata(interfacefile,table.concat(texresult,"\n")) + logs.simple("messages for '%s' saved in '%s'",interface,interfacefile) end end end diff --git a/scripts/context/lua/mtx-patterns.lua b/scripts/context/lua/mtx-patterns.lua index c3817e9a8..a51ca5860 100644 --- a/scripts/context/lua/mtx-patterns.lua +++ b/scripts/context/lua/mtx-patterns.lua @@ -6,95 +6,111 @@ if not modules then modules = { } end modules ['mtx-patterns'] = { license = "see context related readme files" } -local format, find, concat = string.format, string.find, table.concat +local format, find, concat, gsub, match, gmatch = string.format, string.find, table.concat, string.gsub, string.match, string.gmatch +local byte, char = utf.byte, utf.char +local addsuffix = file.addsuffix +local lpegmatch, validutf8 = lpeg.match, lpeg.patterns.validutf8 scripts = scripts or { } scripts.patterns = scripts.patterns or { } + +local permitted_characters = table.tohash { + 0x0009, -- tab + 0x0027, -- apostrofe + 0x02BC, -- modifier apostrofe (used in greek) + 0x002D, -- hyphen + 0x200C, -- zwnj + 0x2019, -- quote right + 0x1FBD, -- greek, but no letter: symbol modifier + 0x1FBF, -- greek, but no letter: symbol modifier +} + +local ignored_ancient_greek = table.tohash { + 0x1FD3, -- greekiotadialytikatonos (also 0x0390) + 0x1FE3, -- greekupsilondialytikatonos (also 0x03B0) + 0x1FBD, -- greek, but no letter: symbol modifier + 0x1FBF, -- greek, but no letter: symbol modifier + 0x03F2, -- greeksigmalunate + 0x02BC, -- modifier apostrofe) +} + +local ignored_french = table.tohash { + 0x02BC, -- modifier apostrofe +} + +local replaced_whatever = { + [char(0x2019)] = char(0x0027) +} + scripts.patterns.list = { - -- no patterns for arabic --- { "ar", "hyph-ar.tex", "arabic" }, - -- not supported --- { "as", "hyph-as.tex", "assamese" }, - { "bg", "hyph-bg.tex", "bulgarian" }, - -- not supported --- { "bn", "hyph-bn.tex", "bengali" }, - { "ca", "hyph-ca.tex", "catalan" }, - -- not supported --- { "cop", "hyph-cop.tex", "coptic" }, - { "cs", "hyph-cs.tex", "czech" }, - { "cy", "hyph-cy.tex", "welsh" }, - { "da", "hyph-da.tex", "danish" }, - { "deo", "hyph-de-1901.tex", "german, old spelling" }, - { "de", "hyph-de-1996.tex", "german, new spelling" }, - { "??", "hyph-de-ch-1901.tex", "swiss german" }, ---~ { "??", "hyph-el-monoton.tex", "" }, ---~ { "??", "hyph-el-polyton.tex", "" }, - { "agr", "hyph-grc.tex", "ancient greek" }, - { "gb", "hyph-en-gb.tex", "british english" }, - { "us", "hyph-en-us.tex", "american english" }, ---~ { "gr", "", "" }, - -- these patterns do not satisfy the rules of 'clean patterns' --- { "eo", "hyph-eo.tex", "esperanto" }, - { "es", "hyph-es.tex", "spanish" }, - { "et", "hyph-et.tex", "estonian" }, - { "eu", "hyph-eu.tex", "basque" }, - -- no patterns for farsi/persian --- { "fa", "hyph-fa.tex", "farsi" }, - { "fi", "hyph-fi.tex", "finnish" }, - { "fr", "hyph-fr.tex", "french" }, - { "??", "hyph-ga.tex", "irish" }, - { "??", "hyph-gl.tex", "galician" }, - -- not supported --- { "gu", "hyph-gu.tex", "gujarati" }, - -- not supported --- { "hi", "hyph-hi.tex", "hindi" }, - { "hr", "hyph-hr.tex", "croatian" }, - { "??", "hyph-hsb.tex", "upper sorbian" }, - { "hu", "hyph-hu.tex", "hungarian" }, - -- not supported --- { "hy", "hyph-hy.tex", "armenian" }, - { "??", "hyph-ia.tex", "interlingua" }, - { "??", "hyph-id.tex", "indonesian" }, - { "is", "hyph-is.tex", "icelandic" }, - { "it", "hyph-it.tex", "italian" }, - { "??", "hyph-kmr.tex", "kurmanji" }, - -- not supported --- { "kn", "hyph-kn.tex", "kannada" }, - { "la", "hyph-la.tex", "latin" }, - -- not supported --- { "lo", "hyph-lo.tex", "lao" }, - { "lt", "hyph-lt.tex", "lithuanian" }, - { "??", "hyph-lv.tex", "latvian" }, - { "mn", "hyph-mn-cyrl.tex", "mongolian, cyrillic script" }, - { "nb", "hyph-nb.tex", "norwegian bokmål" }, - { "nl", "hyph-nl.tex", "dutch" }, - { "nn", "hyph-nn.tex", "norwegian nynorsk" }, - -- not supported --- { "or", "hyph-or.tex", "oriya" }, - -- not supported --- { "pa", "hyph-pa.tex", "panjabi" }, - -- not supported --- { "", "hyph-.tex", "" }, - { "pl", "hyph-pl.tex", "polish" }, - { "pt", "hyph-pt.tex", "portuguese" }, - { "ro", "hyph-ro.tex", "romanian" }, - { "ru", "hyph-ru.tex", "russian" }, - -- not supported --- { "sa", "hyph-sa.tex", "sanskrit" }, - { "sk", "hyph-sk.tex", "slovak" }, - { "sl", "hyph-sl.tex", "slovenian" }, - -- TODO: there is both Cyrillic and Latin script available - { "sr", "hyph-sr-cyrl.tex", "serbian" }, - { "sv", "hyph-sv.tex", "swedish" }, - -- not supported --- { "ta", "hyph-ta.tex", "tamil" }, - -- not supported --- { "te", "hyph-te.tex", "telugu" }, - { "tk", "hyph-tk.tex", "turkmen" }, - { "tr", "hyph-tr.tex", "turkish" }, - { "uk", "hyph-uk.tex", "ukrainian" }, - { "zh", "hyph-zh-latn.tex", "zh-latn, chinese Pinyin" }, + -- { "ar", "hyph-ar", "arabic" }, + -- { "as", "hyph-as", "assamese" }, + { "bg", "hyph-bg", "bulgarian" }, + -- { "bn", "hyph-bn", "bengali" }, + { "ca", "hyph-ca", "catalan" }, + -- { "??", "hyph-cop", "coptic" }, + { "cs", "hyph-cs", "czech" }, + { "cy", "hyph-cy", "welsh" }, + { "da", "hyph-da", "danish" }, + { "deo", "hyph-de-1901", "german, old spelling" }, + { "de", "hyph-de-1996", "german, new spelling" }, + -- { "??", "hyph-de-ch-1901", "swiss german" }, + -- { "??", "hyph-el-monoton", "greek" }, + -- { "gr", "hyph-el-polyton", "greek" }, + { "agr", "hyph-grc", "ancient greek", ignored_ancient_greek }, + { "gb", "hyph-en-gb", "british english" }, + { "us", "hyph-en-us", "american english" }, + -- { "eo", "hyph-eo", "esperanto" }, + { "es", "hyph-es", "spanish" }, + { "et", "hyph-et", "estonian" }, + { "eu", "hyph-eu", "basque" }, + -- { "fa", "hyph-fa", "farsi" }, + { "fi", "hyph-fi", "finnish" }, + { "fr", "hyph-fr", "french", ignored_french }, + -- { "??", "hyph-ga", "irish" }, + -- { "??", "hyph-gl", "galician" }, + -- { "gu", "hyph-gu", "gujarati" }, + -- { "hi", "hyph-hi", "hindi" }, + { "hr", "hyph-hr", "croatian" }, + -- { "??", "hyph-hsb", "upper sorbian" }, + { "hu", "hyph-hu", "hungarian" }, + -- { "hy", "hyph-hy", "armenian" }, + -- { "??", "hyph-ia", "interlingua" }, + -- { "??", "hyph-id", "indonesian" }, + { "is", "hyph-is", "icelandic" }, + { "it", "hyph-it", "italian" }, + -- { "??", "hyph-kmr", "kurmanji" }, + -- { "kn", "hyph-kn", "kannada" }, + { "la", "hyph-la", "latin" }, + -- { "lo", "hyph-lo", "lao" }, + { "lt", "hyph-lt", "lithuanian" }, + { "lv", "hyph-lv", "latvian" }, + -- { "ml", "hyph-ml", "..." }, + { "mn", "hyph-mn-cyrl", "mongolian, cyrillic script" }, + -- { "mr", "hyph-mr", "..." }, + { "nb", "hyph-nb", "norwegian bokmål" }, + { "nl", "hyph-nl", "dutch" }, + { "nn", "hyph-nn", "norwegian nynorsk" }, + -- { "or", "hyph-or", "oriya" }, + -- { "pa", "hyph-pa", "panjabi" }, + -- { "", "hyph-", "" }, + { "pl", "hyph-pl", "polish" }, + { "pt", "hyph-pt", "portuguese" }, + { "ro", "hyph-ro", "romanian" }, + { "ru", "hyph-ru", "russian" }, + -- { "sa", "hyph-sa", "sanskrit" }, + { "sk", "hyph-sk", "slovak" }, + { "sl", "hyph-sl", "slovenian" }, + { "sr", "hyph-sr-cyrl", "serbian" }, + -- { "sr", "hyph-sr-latn", "serbian" }, + { "sv", "hyph-sv", "swedish" }, + -- { "ta", "hyph-ta", "tamil" }, + -- { "te", "hyph-te", "telugu" }, + { "tk", "hyph-tk", "turkmen" }, + { "tr", "hyph-tr", "turkish" }, + { "uk", "hyph-uk", "ukrainian" }, + { "zh", "hyph-zh-latn", "zh-latn, chinese pinyin" }, } -- stripped down from lpeg example: @@ -105,189 +121,220 @@ function utf.check(str) return lpeg.match(lpeg.patterns.validutf8,str) end -local permitted_commands = table.tohash { - "message", - "endinput" -} - -local permitted_characters = table.tohash { - 0x0009, -- tab - 0x0027, -- apostrofe - 0x002D, -- hyphen - 0x200C, -- -} +-- *.tex +-- *.hyp.txt *.pat.txt *.lic.txt *.chr.txt -function scripts.patterns.load(path,name,mnemonic,fullcheck) +function scripts.patterns.load(path,name,mnemonic,ignored) local fullname = file.join(path,name) - local data = io.loaddata(fullname) or "" - local byte, char = utf.byte, utf.char - if data ~= "" then - data = data:gsub("([\n\r])\\input ([^ \n\r]+)", function(previous,subname) - local subname = file.addsuffix(subname,"tex") - local subfull = file.join(file.dirname(fullname),subname) - local subdata = io.loaddata(subfull) or "" - if subdata == "" then - if mnemonic then - logs.simple("no subfile %s for language %s",subname,mnemonic) - else - logs.simple("no subfile %s",name) + local texfile = addsuffix(fullname,"tex") + local hypfile = addsuffix(fullname,"hyp.txt") + local patfile = addsuffix(fullname,"pat.txt") + local licfile = addsuffix(fullname,"lic.txt") + -- local chrfile = addsuffix(fullname,"chr.txt") + local okay = true + local hyphenations, patterns, comment, stripset = "", "", "", "" + local splitpatternsnew, splithyphenationsnew = { }, { } + local splitpatternsold, splithyphenationsold = { }, { } + local usedpatterncharacters, usedhyphenationcharacters = { }, { } + if lfs.isfile(patfile) then + logs.simple("using txt files %s.[hyp|pat|lic].txt",name) + comment, patterns, hyphenations = io.loaddata(licfile) or "", io.loaddata(patfile) or "", io.loaddata(hypfile) or "" + hypfile, patfile, licfile = hypfile, patfile, licfile + elseif lfs.isfile(texfile) then + logs.simple("using tex file %s.txt",name) + local data = io.loaddata(texfile) or "" + if data ~= "" then + data = gsub(data,"([\n\r])\\input ([^ \n\r]+)", function(previous,subname) + local subname = addsuffix(subname,"tex") + local subfull = file.join(file.dirname(texfile),subname) + local subdata = io.loaddata(subfull) or "" + if subdata == "" then + logs.simple("no subfile %s",subname) end - end - return previous .. subdata - end) - local comment = data:match("^(.-)[\n\r]\\patterns") or "" - local n, okay = 0, true - local cd = characters.data - for line in data:gmatch("[^ \n\r]+") do - local ok = utf.check(line) - n = n + 1 - if not ok then - okay = false - line = line:gsub("%%","%%%%") - if fullcheck then - if mnemonic then - logs.simple("invalid utf in language %s, file %s, line %s: %s",mnemonic,name,n,line) - else - logs.simple("invalid utf in file %s, line %s: %s",name,n,line) - end - else - if mnemonic then - logs.simple("file %s for %s contains invalid utf",name,mnemonic) - else - logs.simple("file %s contains invalid utf",name) + return previous .. subdata + end) + data = gsub(data,"%%.-[\n\r]","") + data = gsub(data," *[\n\r]+","\n") + patterns = match(data,"\\patterns[%s]*{[%s]*(.-)[%s]*}") or "" + hyphenations = match(data,"\\hyphenation[%s]*{[%s]*(.-)[%s]*}") or "" + comment = match(data,"^(.-)[\n\r]\\patterns") or "" + else + okay = false + end + else + okay = false + end + if okay then + -- split into lines + local how = lpeg.patterns.whitespace^1 + splitpatternsnew = lpeg.split(how,patterns) + splithyphenationsnew = lpeg.split(how,hyphenations) + end + if okay then + -- remove comments + local function check(data,splitdata,name) + if find(data,"%%") then + for i=1,#splitdata do + local line = splitdata[i] + if find(line,"%%") then + splitdata[i] = gsub(line,"%%.*$","") + logs.simple("removing comment: %s",line) end - break end end end - local c, h = { }, { } - for line in data:gmatch("[^\n\r]+") do - local txt, cmt = line:match("^(.-)%%(.*)$") - if not txt then - txt, cmt = line, "" - end - for s in txt:gmatch("\\([a-zA-Z]+)") do - h[s] = (h[s] or 0) + 1 - end - for s in cmt:gmatch("\\([a-zA-Z]+)") do - c[s] = (c[s] or 0) + 1 - end - end - h.patterns = nil - h.hyphenation = nil - for k, v in next, h do - if not permitted_commands[k] then okay = false end - if mnemonic then - logs.simple("command \\%s found in language %s, file %s, n=%s",k,mnemonic,name,v) - else - logs.simple("command \\%s found in file %s, n=%s",k,name,v) + check(patterns,splitpatternsnew,patfile) + check(hyphenations,splithyphenationsnew,hypfile) + end + if okay then + -- remove lines with commands + local function check(data,splitdata,name) + if find(data,"\\") then + for i=1,#splitdata do + local line = splitdata[i] + if find(line,"\\") then + splitdata[i] = "" + logs.simple("removing line with command: %s",line) + end + end end end - if not environment.argument("fast") then - for k, v in next, c do - if mnemonic then - logs.simple("command \\%s found in comment of language %s, file %s, n=%s",k,mnemonic,name,v) - else - logs.simple("command \\%s found in comment of file %s, n=%s",k,name,v) + check(patterns,splitpatternsnew,patfile) + check(hyphenations,splithyphenationsnew,hypfile) + end + if okay then + -- check for valid utf + local function check(data,splitdata,name) + for i=1,#splitdata do + local line = splitdata[i] + local ok = lpegmatch(validutf8,line) + if not ok then + splitdata[i] = "" + logs.simple("removing line with invalid utf: %s",line) end end + -- check for commands being used in comments end - data = data:gsub("%%.-[\n\r]","") - data = data:gsub(" *[\n\r]+","\n") - local patterns = data:match("\\patterns[%s]*{[%s]*(.-)[%s]*}") or "" - local hyphenations = data:match("\\hyphenation[%s]*{[%s]*(.-)[%s]*}") or "" - patterns = patterns:gsub("[ \t]+","\n") - hyphenations = hyphenations:gsub("[ \t]+","\n") - local p, h = { }, { } - local pats, hyps = { } , { } - local pused, hused = { } , { } - local period = byte(".") - for line in patterns:gmatch("[^ \n\r]+") do - local ok = true - for b in line:utfvalues() do - if b == period then - -- ok - else - local ct = cd[b].category - if ct == "lu" or ct == "ll" then - pused[char(b)] = true - elseif ct == "nd" then - -- ok + check(patterns,splitpatternsnew,patfile) + check(hyphenations,splithyphenationsnew,hypfile) + end + if okay then + -- remove funny lines + local cd = characters.data + local stripped = { } + local function check(splitdata,special,name) + local used = { } + for i=1,#splitdata do + local line = splitdata[i] + for b in line:utfvalues() do -- could be an lpeg + if b == special then + -- not registered + elseif permitted_characters[b] then + used[char(b)] = true else - p[b] = (p[b] or 0) + 1 - ok = false + local cdb = cd[b] + if not cdb then + logs.simple("no entry in chardata for character %s (0x%04X)",char(b),b) + else + local ct = cd[b].category + if ct == "lu" or ct == "ll" then + used[char(b)] = true + elseif ct == "nd" then + -- number + else + logs.simple("removing line with suspected utf character %s (0x%04X), category %s: %s",char(b),b,ct,line) + splitdata[i] = "" + break + end + end end end end - if ok then - pats[#pats+1] = line - end + return used end - local hyphen = byte("-") - for line in hyphenations:gmatch("[^ \n\r]+") do - local ok = true - for b in line:utfvalues() do - if b == hyphen then - -- ok - else - local ct = cd[b].category - if ct == "lu" or ct == "ll" then - hused[char(b)] = true + usedpatterncharacters = check(splitpatternsnew,byte(".")) + usedhyphenationcharacters = check(splithyphenationsnew,byte("-")) + for k, v in next, stripped do + logs.simple("entries that contain character %s (0x%04X) have been omitted",char(k),k) + end + end + if okay then + local function stripped(what,ignored) + -- ignored (per language) + local p = nil + if ignored then + for k, v in next, ignored do + if p then + p = p + lpeg.P(char(k)) else - h[b] = (h[b] or 0) + 1 - ok = false + p = lpeg.P(char(k)) end end + p = lpeg.P{ p + 1 * lpeg.V(1) } -- anywhere end - if ok then - hyps[#hyps+1] = line - end - end - local stripped = { } - for k, v in next, p do - if mnemonic then - logs.simple("invalid character %s (0x%04X) in patterns of language %s, file %s, n=%s",char(k),k,mnemonic,name,v) - else - logs.simple("invalid character %s (0x%04X) in patterns of file %s, n=%s",char(k),k,name,v) + -- replaced (all languages) + local r = nil + for k, v in next, replaced_whatever do + if r then + r = r + lpeg.P(k)/v + else + r = lpeg.P(k)/v + end end - if not permitted_characters[k] then - okay = false - else - stripped[k] = true + r = lpeg.Cs((r + 1)^0) + local result = { } + for i=1,#what do + local line = what[i] + if p and lpegmatch(p,line) then + logs.simple("discarding conflicting pattern: %s",line) + else -- we can speed this up by testing for replacements in the string + local l = lpegmatch(r,line) + if l ~= line then + logs.simple("sanitizing pattern: %s -> %s (for old patterns)",line,l) + end + result[#result+1] = l + end end + return result end - for k, v in next, h do - if mnemonic then - logs.simple("invalid character %s (0x%04X) in exceptions of language %s, file %s, n=%s",char(k),k,mnemonic,name,v) - else - logs.simple("invalid character %s (0x%04X) in exceptions of file %s, n=%s",char(k),k,name,v) - end - if not permitted_characters[k] then - okay = false - else - stripped[k] = true + + splitpatternsold = stripped(splitpatternsnew,ignored) + splithyphenationsold = stripped(splithyphenationsnew,ignored) + + end + if okay then + -- discarding duplicates + local function check(data,splitdata,name) + local used, collected = { }, { } + for i=1,#splitdata do + local line = splitdata[i] + if line == "" then + -- discard + elseif used[line] then + -- discard + logs.simple("discarding duplicate pattern: %s",line) + else + used[line] = true + collected[#collected+1] = line + end end + return collected end - local stripset = "" - for k, v in next, stripped do - logs.simple("entries that contain character %s will be omitted",char(k)) - stripset = stripset .. "%" .. char(k) - end - return okay, pats, hyps, comment, stripset, pused, hused - else - if mnemonic then - logs.simple("no file %s for language %s",fullname,mnemonic) - else - logs.simple("no file %s",fullname) - end - return false, { }, { }, "", "", { }, { } + splitpatternsnew = check(patterns,splitpatternsnew,patfile) + splithyphenationsnew = check(hyphenations,splithyphenationsnew,hypfile) + splitpatternsold = check(patterns,splitpatternsold,patfile) + splithyphenationsold = check(hyphenations,splithyphenationsold,hypfile) + end + if not okay then + logs.simple("no valid file %s.*",name) end + return okay, splitpatternsnew, splithyphenationsnew, splitpatternsold, splithyphenationsold, comment, stripset, usedpatterncharacters, usedhyphenationcharacters end -function scripts.patterns.save(destination,mnemonic,name,patterns,hyphenations,comment,stripped,pused,hused) - local nofpatterns = #patterns - local nofhyphenations = #hyphenations - logs.simple("language %s has %s patterns and %s exceptions",mnemonic,nofpatterns,nofhyphenations) +function scripts.patterns.save(destination,mnemonic,name,patternsnew,hyphenationsnew,patternsold,hyphenationsold,comment,stripped,pused,hused,ignored) + local nofpatternsnew, nofhyphenationsnew = #patternsnew, #hyphenationsnew + local nofpatternsold, nofhyphenationsold = #patternsold, #hyphenationsold + logs.simple("language %s has %s old and %s new patterns and %s old and %s new exceptions",mnemonic,nofpatternsold,nofpatternsnew,nofhyphenationsold,nofhyphenationsnew) if mnemonic ~= "??" then local pu = concat(table.sortedkeys(pused), " ") local hu = concat(table.sortedkeys(hused), " ") @@ -318,28 +365,28 @@ function scripts.patterns.save(destination,mnemonic,name,patterns,hyphenations,c } local patterndata, hyphenationdata - if nofpatterns > 0 then + if nofpatternsnew > 0 then patterndata = { - n = nofpatterns, - data = concat(patterns," ") or nil, + n = nofpatternsnew, + data = concat(patternsnew," ") or nil, characters = concat(table.sortedkeys(pused),""), minhyphenmin = 1, -- determined by pattern author minhyphenmax = 1, -- determined by pattern author } else patterndata = { - n = nofpatterns, + n = 0, } end - if nofhyphenations > 0 then + if nofhyphenationsnew > 0 then hyphenationdata = { - n = nofhyphenations, - data = concat(hyphenations," "), + n = nofhyphenationsnew, + data = concat(hyphenationsnew," "), characters = concat(table.sortedkeys(hused),""), } else hyphenationdata = { - n = nofhyphenations, + n = 0, } end local data = { @@ -358,8 +405,8 @@ function scripts.patterns.save(destination,mnemonic,name,patterns,hyphenations,c os.remove(luafile) io.savedata(rmefile,format("%s\n\n%s",topline,comment)) - io.savedata(patfile,format("%s\n\n%s\n\n%% used: %s\n\n\\patterns{\n%s}",topline,banner,pu,concat(patterns,"\n"))) - io.savedata(hypfile,format("%s\n\n%s\n\n%% used: %s\n\n\\hyphenation{\n%s}",topline,banner,hu,concat(hyphenations,"\n"))) + io.savedata(patfile,format("%s\n\n%s\n\n%% used: %s\n\n\\patterns{\n%s}",topline,banner,pu,concat(patternsold,"\n"))) + io.savedata(hypfile,format("%s\n\n%s\n\n%% used: %s\n\n\\hyphenation{\n%s}",topline,banner,hu,concat(hyphenationsold,"\n"))) io.savedata(luafile,table.serialize(data,true)) end end @@ -370,22 +417,16 @@ end function scripts.patterns.check() local path = environment.argument("path") or "." - local found = false local files = environment.files + local only = false if #files > 0 then - for i=1,#files do - local name = files[i] - logs.simple("checking language file %s", name) - local okay = scripts.patterns.load(path,name,nil,not environment.argument("fast")) - if #environment.files > 1 then - logs.simple("") - end - end - else - for k, v in next, scripts.patterns.list do - local mnemonic, name = v[1], v[2] + only = table.tohash(files) + end + for k, v in next, scripts.patterns.list do + local mnemonic, name, ignored = v[1], v[2], v[4] + if not only or only[mnemonic] then logs.simple("checking language %s, file %s", mnemonic, name) - local okay = scripts.patterns.load(path,name,mnemonic,not environment.argument("fast")) + local okay = scripts.patterns.load(path,name,mnemonic,ignored) if not okay then logs.simple("there are errors that need to be fixed") end @@ -403,16 +444,23 @@ function scripts.patterns.convert() if path == destination then logs.simple("source path and destination path should differ (use --path and/or --destination)") else + local files = environment.files + local only = false + if #files > 0 then + only = table.tohash(files) + end for k, v in next, scripts.patterns.list do - local mnemonic, name = v[1], v[2] - logs.simple("converting language %s, file %s", mnemonic, name) - local okay, patterns, hyphenations, comment, stripped, pused, hused = scripts.patterns.load(path,name,false) - if okay then - scripts.patterns.save(destination,mnemonic,name,patterns,hyphenations,comment,stripped,pused,hused) - else - logs.simple("convertion aborted due to error(s)") + local mnemonic, name, ignored = v[1], v[2], v[4] + if not only or only[mnemonic] then + logs.simple("converting language %s, file %s", mnemonic, name) + local okay, patternsnew, hyphenationsnew, patternsold, hyphenationsold, comment, stripped, pused, hused = scripts.patterns.load(path,name,mnemonic,ignored) + if okay then + scripts.patterns.save(destination,mnemonic,name,patternsnew,hyphenationsnew,patternsold,hyphenationsold,comment,stripped,pused,hused,ignored) + else + logs.simple("convertion aborted due to error(s)") + end + logs.simple("") end - logs.simple("") end end end @@ -425,8 +473,6 @@ messages.help = [[ --check check pattern file (or those used by context when no file given) --path source path where hyph-foo.tex files are stored --destination destination path - ---fast only report filenames, no lines ]] if environment.argument("check") then @@ -441,6 +487,5 @@ end -- mtxrun --script pattern --check hyph-*.tex -- mtxrun --script pattern --check --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns --- mtxrun --script pattern --check --fast --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns --- mtxrun --script pattern --convert --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns --destination=e:/tmp/patterns --- mtxrun --script pattern --convert --path=c:/data/develop/svn-hyphen/branches/luatex/hyph-utf8/tex/generic/hyph-utf8/patterns/tex --destination=e:/tmp/patterns +-- mtxrun --script pattern --convert --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/tex --destination=e:/tmp/patterns +-- mtxrun --script pattern --convert --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/txt --destination=e:/tmp/patterns diff --git a/scripts/context/lua/mtx-server-ctx-fonttest.lua b/scripts/context/lua/mtx-server-ctx-fonttest.lua index b2a993bf8..4415cbd5d 100644 --- a/scripts/context/lua/mtx-server-ctx-fonttest.lua +++ b/scripts/context/lua/mtx-server-ctx-fonttest.lua @@ -17,7 +17,7 @@ local format, gsub, concat, match, find = string.format, string.gsub, table.conc local sample_line = "This is a sample line!" local tempname = "mtx-server-ctx-fonttest-temp" -local temppath = caches.setpath("temp","mtx-server-ctx-fonttest") +local temppath = caches.setfirstwritablefile("temp","mtx-server-ctx-fonttest") local basename = "mtx-server-ctx-fonttest-data.lua" local basepath = temppath diff --git a/scripts/context/lua/mtx-server.lua b/scripts/context/lua/mtx-server.lua index dc0befcaa..b1d1174bb 100644 --- a/scripts/context/lua/mtx-server.lua +++ b/scripts/context/lua/mtx-server.lua @@ -358,4 +358,4 @@ else end --- mtxrun --script server --start => http://localhost:8080/mtx-server-ctx-help.lua +-- mtxrun --script server --start => http://localhost:31415/mtx-server-ctx-startup.lua diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index ac4b0556e..68ee3d2c1 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -347,7 +347,8 @@ patterns.hexadecimal = P("0x") * R("09","AF","af")^1 patterns.lowercase = R("az") patterns.uppercase = R("AZ") patterns.letter = patterns.lowercase + patterns.uppercase -patterns.space = S(" ") +patterns.space = P(" ") +patterns.tab = P("\t") patterns.eol = S("\n\r") patterns.spacer = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto) patterns.newline = crlf + cr + lf @@ -358,6 +359,9 @@ patterns.nonwhitespace = 1 - patterns.whitespace patterns.utf8 = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four patterns.utfbom = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191') patterns.validutf8 = patterns.utf8^0 * P(-1) * Cc(true) + Cc(false) +patterns.comma = P(",") +patterns.commaspacer = P(",") * patterns.spacer^0 +patterns.period = P(".") patterns.undouble = P('"')/"" * (1-P('"'))^0 * P('"')/"" patterns.unsingle = P("'")/"" * (1-P("'"))^0 * P("'")/"" @@ -462,15 +466,36 @@ local function f4(s) local c1, c2, c3, c4 = f1(s,1,4) return ((c1 * 64 + c2) * 6 patterns.utf8byte = patterns.utf8one/f1 + patterns.utf8two/f2 + patterns.utf8three/f3 + patterns.utf8four/f4 + + local cache = { } function lpeg.stripper(str) - local s = cache[str] - if not s then - s = Cs(((S(str)^1)/"" + 1)^0) - cache[str] = s + if type(str) == "string" then + local s = cache[str] + if not s then + s = Cs(((S(str)^1)/"" + 1)^0) + cache[str] = s + end + return s + else + return Cs(((str^1)/"" + 1)^0) + end +end + +local cache = { } + +function lpeg.keeper(str) + if type(str) == "string" then + local s = cache[str] + if not s then + s = Cs((((1-S(str))^1)/"" + 1)^0) + cache[str] = s + end + return s + else + return Cs((((1-str)^1)/"" + 1)^0) end - return s end function lpeg.replacer(t) @@ -642,7 +667,7 @@ end table.sortedkeys = sortedkeys table.sortedhashkeys = sortedhashkeys -function table.sortedhash(t) +local function sortedhash(t) local s = sortedhashkeys(t) -- maybe just sortedkeys local n = 0 local function kv(s) @@ -653,7 +678,8 @@ function table.sortedhash(t) return kv, s end -table.sortedpairs = table.sortedhash +table.sortedhash = sortedhash +table.sortedpairs = sortedhash function table.append(t, list) for _,v in next, list do @@ -1315,12 +1341,17 @@ function table.count(t) return n end -function table.swapped(t) - local s = { } +function table.swapped(t,s) + local n = { } + if s then + for k, v in next, s do + n[k] = v + end + end for k, v in next, t do - s[v] = k + n[v] = k end - return s + return n end @@ -1340,7 +1371,7 @@ function table.hexed(t,seperator) return concat(tt,seperator or " ") end -function table.reverse_hash(h) +function table.reverse_hash(h) -- needs another name local r = { } for k,v in next, h do r[v] = lower(gsub(k," ","")) @@ -1388,10 +1419,18 @@ function table.insert_after_value(t,value,extra) insert(t,#t+1,extra) end -function table.sequenced(t,sep) +function table.sequenced(t,sep,simple) -- hash only local s = { } - for k, v in next, t do -- indexed? - s[#s+1] = k .. "=" .. tostring(v) + for k, v in sortedhash(t) do + if simple then + if v == true then + s[#s+1] = k + elseif v and v~= "" then + s[#s+1] = k .. "=" .. tostring(v) + end + else + s[#s+1] = k .. "=" .. tostring(v) + end end return concat(s, sep or " | ") end @@ -1593,6 +1632,39 @@ function io.ask(question,default,options) end end +function io.readnumber(f,n,m) + if m then + f:seek("set",n) + n = m + end + if n == 1 then + return byte(f:read(1)) + elseif n == 2 then + local a, b = byte(f:read(2),1,2) + return 256*a + b + elseif n == 4 then + local a, b, c, d = byte(f:read(4),1,4) + return 256^3 * a + 256^2 * b + 256*c + d + elseif n == 8 then + local a, b = readnumber(f,4), readnumber(f,4) + return 256 * b + c + elseif n == 12 then + local a, b, c = readnumber(f,4), readnumber(f,4), readnumber(f,4) + return 256^2 * a + 256 * b + c + else + return 0 + end +end + +function io.readstring(f,n,m) + if m then + f:seek("set",n) + n = m + end + local str = gsub(f:read(n),"%z","") + return str +end + end -- of closure @@ -1658,6 +1730,23 @@ function number.bits(n,zero) end +function number.bit(p) + return 2 ^ (p - 1) -- 1-based indexing +end + +function number.hasbit(x, p) -- typical call: if hasbit(x, bit(3)) then ... + return x % (p + p) >= p +end + +function number.setbit(x, p) + return hasbit(x, p) and x or x + p +end + +function number.clearbit(x, p) + return hasbit(x, p) and x - p or x +end + + end -- of closure do -- create closure to overcome 200 locals limit @@ -3023,7 +3112,7 @@ end utf = utf or unicode.utf8 local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub -local char, byte, find, bytepairs = string.char, string.byte, string.find, string.bytepairs +local char, byte, find, bytepairs, utfvalues, format = string.char, string.byte, string.find, string.bytepairs, string.utfvalues, string.format -- 0 EF BB BF UTF-8 -- 1 FF FE UTF-16-little-endian @@ -3189,6 +3278,15 @@ function unicode.utf8_to_utf16(str,littleendian) end end +function unicode.utfcodes(str) + local t = { } + for k,v in string.utfvalues(str) do + t[#t+1] = format("0x%04X",k) + end + return concat(t,separator or " ") +end + + end -- of closure @@ -3568,14 +3666,24 @@ function aux.array_to_string(a,separator) end end -function aux.settings_to_set(str,t) +function aux.settings_to_set(str,t) -- tohash? t = t or { } - for s in gmatch(str,"%s*([^,]+)") do + for s in gmatch(str,"%s*([^, ]+)") do -- space added t[s] = true end return t end +function aux.simple_hash_to_string(h, separator) + local t = { } + for k, v in table.sortedhash(h) do + if v then + t[#t+1] = k + end + end + return concat(t,separator or ",") +end + local value = lbrace * lpeg.C((nobrace + nested)^0) * rbrace local pattern = lpeg.Ct((space + value)^0) @@ -3637,6 +3745,60 @@ end -- as we use this a lot ... +function aux.formatcolumns(result,between) + if result and #result > 0 then + between = between or " " + local widths, numbers = { }, { } + local first = result[1] + local n = #first + for i=1,n do + widths[i] = 0 + end + for i=1,#result do + local r = result[i] + for j=1,n do + local rj = r[j] + local tj = type(rj) + if tj == "number" then + numbers[j] = true + end + if tj ~= "string" then + rj = tostring(rj) + r[j] = rj + end + local w = #rj + if w > widths[j] then + widths[j] = w + end + end + end + for i=1,n do + local w = widths[i] + if numbers[i] then + if w > 80 then + widths[i] = "%s" .. between + else + widths[i] = "%0" .. w .. "i" .. between + end + else + if w > 80 then + widths[i] = "%s" .. between + elseif w > 0 then + widths[i] = "%-" .. w .. "s" .. between + else + widths[i] = "%s" + end + end + end + local template = string.strip(concat(widths)) + for i=1,#result do + local str = format(template,unpack(result[i])) + result[i] = string.strip(str) + end + end + return result +end + end -- of closure @@ -3843,7 +4005,7 @@ if not modules then modules = { } end modules ['trac-set'] = { local type, next, tostring = type, next, tostring local concat = table.concat -local format, find, lower, gsub = string.format, string.find, string.lower, string.gsub +local format, find, lower, gsub, simpleesc = string.format, string.find, string.lower, string.gsub, string.simpleesc local is_boolean = string.is_boolean setters = { } @@ -3915,7 +4077,7 @@ local function set(t,what,newvalue) for name, functions in next, data do if done[name] then -- prevent recursion due to wildcards - elseif find(name,w) then + elseif find(name,simpleesc(w)) then done[name] = true for i=1,#functions do functions[i](value) @@ -3979,14 +4141,14 @@ end function setters.enable(t,what) local e = t.enable t.enable, t.done = enable, { } - enable(t,string.simpleesc(tostring(what))) + enable(t,what) t.enable, t.done = e, { } end function setters.disable(t,what) local e = t.disable t.disable, t.done = disable, { } - disable(t,string.simpleesc(tostring(what))) + disable(t,what) t.disable, t.done = e, { } end @@ -4050,36 +4212,50 @@ trackers = setters.new("trackers") directives = setters.new("directives") experiments = setters.new("experiments") +-- experiment + +if trackers and environment and environment.engineflags.trackers then + trackers.enable(environment.engineflags.trackers) +end +if directives and environment and environment.engineflags.directives then + directives.enable(environment.engineflags.directives) +end + -- nice trick: we overload two of the directives related functions with variants that -- do tracing (itself using a tracker) .. proof of concept +local function report(...) -- messy .. chicken or egg + local p = (commands and commands.writestatus) or (logs and logs.report) + if p then p(...) end +end + local trace_directives = false local trace_directives = false trackers.register("system.directives", function(v) trace_directives = v end) local trace_experiments = false local trace_experiments = false trackers.register("system.experiments", function(v) trace_experiments = v end) -local e = directives.enable -local d = directives.disable +local enable = directives.enable +local disable = directives.disable function directives.enable(...) - (commands.writestatus or logs.report)("directives","enabling: %s",concat({...}," ")) - e(...) + report("directives","enabling: %s",concat({...}," ")) + enable(...) end function directives.disable(...) - (commands.writestatus or logs.report)("directives","disabling: %s",concat({...}," ")) - d(...) + report("directives","disabling: %s",concat({...}," ")) + disable(...) end -local e = experiments.enable -local d = experiments.disable +local enable = experiments.enable +local disable = experiments.disable function experiments.enable(...) - (commands.writestatus or logs.report)("experiments","enabling: %s",concat({...}," ")) - e(...) + report("experiments","enabling: %s",concat({...}," ")) + enable(...) end function experiments.disable(...) - (commands.writestatus or logs.report)("experiments","disabling: %s",concat({...}," ")) - d(...) + report("experiments","disabling: %s",concat({...}," ")) + disable(...) end -- a useful example @@ -4088,6 +4264,15 @@ directives.register("system.nostatistics", function(v) statistics.enable = not v end) +-- experiment + +if trackers and environment and environment.engineflags.trackers then + trackers.enable(environment.engineflags.trackers) +end +if directives and environment and environment.engineflags.directives then + directives.enable(environment.engineflags.directives) +end + end -- of closure @@ -6357,17 +6542,19 @@ apply_axis['child'] = function(list) for l=1,#list do local ll = list[l] local dt = ll.dt - local en = 0 - for k=1,#dt do - local dk = dt[k] - if dk.tg then - collected[#collected+1] = dk - dk.ni = k -- refresh - en = en + 1 - dk.ei = en + if dt then -- weird that this is needed + local en = 0 + for k=1,#dt do + local dk = dt[k] + if dk.tg then + collected[#collected+1] = dk + dk.ni = k -- refresh + en = en + 1 + dk.ei = en + end end + ll.en = en end - ll.en = en end return collected end @@ -8079,6 +8266,7 @@ local finalizers = xml.finalizers.xml local xmlfilter = xml.filter -- we could inline this one for speed local xmltostring = xml.tostring local xmlserialize = xml.serialize +local xmlcollected = xml.collected local function first(collected) -- wrong ? return collected and collected[1] @@ -8356,6 +8544,19 @@ xml.all = xml.filter xml.index = xml.position xml.found = xml.filter +-- a nice one: + +local function totable(x) + local t = { } + for e in xmlcollected(x[1] or x,"/*") do + t[e.tg] = xmltostring(e.dt) or "" + end + return next(t) and t or nil +end + +xml.table = totable +finalizers.table = totable + end -- of closure @@ -8943,6 +9144,7 @@ formats['pfb'] = 'T1FONTS' suffixes['pfb'] = { 'pfb', ' formats['vf'] = 'VFFONTS' suffixes['vf'] = { 'vf' } formats['fea'] = 'FONTFEATURES' suffixes['fea'] = { 'fea' } formats['cid'] = 'FONTCIDMAPS' suffixes['cid'] = { 'cid', 'cidmap' } +formats['icc'] = 'ICCPROFILES' suffixes['icc'] = { 'icc' } formats['texmfscripts'] = 'TEXMFSCRIPTS' suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } formats['lua'] = 'LUAINPUTS' suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' } formats['lib'] = 'CLUAINPUTS' suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' } @@ -8958,6 +9160,7 @@ alternatives['truetype fonts'] = 'ttf' alternatives['truetype collections'] = 'ttc' alternatives['truetype dictionary'] = 'dfont' alternatives['type1 fonts'] = 'pfb' +alternatives['icc profiles'] = 'icc' --[[ldx-- <p>If you wondered about some of the previous mappings, how about @@ -12160,6 +12363,21 @@ if not modules then modules = { } end modules ['luat-fmt'] = { -- helper for mtxrun +local quote = string.quote + +local function primaryflags() + local trackers = environment.argument("trackers") + local directives = environment.argument("directives") + local flags = "" + if trackers and trackers ~= "" then + flags = flags .. "--trackers=" .. quote(trackers) + end + if directives and directives ~= "" then + flags = flags .. "--directives=" .. quote(directives) + end + return flags +end + function environment.make_format(name) -- change to format path (early as we need expanded paths) local olddir = lfs.currentdir() @@ -12220,8 +12438,7 @@ function environment.make_format(name) return end -- generate format - local q = string.quote - local command = string.format("luatex --ini --lua=%s %s %sdump",q(usedluastub),q(fulltexsourcename),os.platform == "unix" and "\\\\" or "\\") + local command = string.format("luatex --ini %s --lua=%s %s %sdump",primaryflags(),quote(usedluastub),quote(fulltexsourcename),os.platform == "unix" and "\\\\" or "\\") logs.simple("running command: %s\n",command) os.spawn(command) -- remove related mem files @@ -12260,7 +12477,7 @@ function environment.run_format(name,data,more) logs.simple("no luc/lua with name: %s",barename) else local q = string.quote - local command = string.format("luatex --fmt=%s --lua=%s %s %s",q(barename),q(luaname),q(data),more ~= "" and q(more) or "") + local command = string.format("luatex %s --fmt=%s --lua=%s %s %s",primaryflags(),quote(barename),quote(luaname),quote(data),more ~= "" and quote(more) or "") logs.simple("running command: %s",command) os.spawn(command) end diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index ac4b0556e..68ee3d2c1 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -347,7 +347,8 @@ patterns.hexadecimal = P("0x") * R("09","AF","af")^1 patterns.lowercase = R("az") patterns.uppercase = R("AZ") patterns.letter = patterns.lowercase + patterns.uppercase -patterns.space = S(" ") +patterns.space = P(" ") +patterns.tab = P("\t") patterns.eol = S("\n\r") patterns.spacer = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto) patterns.newline = crlf + cr + lf @@ -358,6 +359,9 @@ patterns.nonwhitespace = 1 - patterns.whitespace patterns.utf8 = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four patterns.utfbom = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191') patterns.validutf8 = patterns.utf8^0 * P(-1) * Cc(true) + Cc(false) +patterns.comma = P(",") +patterns.commaspacer = P(",") * patterns.spacer^0 +patterns.period = P(".") patterns.undouble = P('"')/"" * (1-P('"'))^0 * P('"')/"" patterns.unsingle = P("'")/"" * (1-P("'"))^0 * P("'")/"" @@ -462,15 +466,36 @@ local function f4(s) local c1, c2, c3, c4 = f1(s,1,4) return ((c1 * 64 + c2) * 6 patterns.utf8byte = patterns.utf8one/f1 + patterns.utf8two/f2 + patterns.utf8three/f3 + patterns.utf8four/f4 + + local cache = { } function lpeg.stripper(str) - local s = cache[str] - if not s then - s = Cs(((S(str)^1)/"" + 1)^0) - cache[str] = s + if type(str) == "string" then + local s = cache[str] + if not s then + s = Cs(((S(str)^1)/"" + 1)^0) + cache[str] = s + end + return s + else + return Cs(((str^1)/"" + 1)^0) + end +end + +local cache = { } + +function lpeg.keeper(str) + if type(str) == "string" then + local s = cache[str] + if not s then + s = Cs((((1-S(str))^1)/"" + 1)^0) + cache[str] = s + end + return s + else + return Cs((((1-str)^1)/"" + 1)^0) end - return s end function lpeg.replacer(t) @@ -642,7 +667,7 @@ end table.sortedkeys = sortedkeys table.sortedhashkeys = sortedhashkeys -function table.sortedhash(t) +local function sortedhash(t) local s = sortedhashkeys(t) -- maybe just sortedkeys local n = 0 local function kv(s) @@ -653,7 +678,8 @@ function table.sortedhash(t) return kv, s end -table.sortedpairs = table.sortedhash +table.sortedhash = sortedhash +table.sortedpairs = sortedhash function table.append(t, list) for _,v in next, list do @@ -1315,12 +1341,17 @@ function table.count(t) return n end -function table.swapped(t) - local s = { } +function table.swapped(t,s) + local n = { } + if s then + for k, v in next, s do + n[k] = v + end + end for k, v in next, t do - s[v] = k + n[v] = k end - return s + return n end @@ -1340,7 +1371,7 @@ function table.hexed(t,seperator) return concat(tt,seperator or " ") end -function table.reverse_hash(h) +function table.reverse_hash(h) -- needs another name local r = { } for k,v in next, h do r[v] = lower(gsub(k," ","")) @@ -1388,10 +1419,18 @@ function table.insert_after_value(t,value,extra) insert(t,#t+1,extra) end -function table.sequenced(t,sep) +function table.sequenced(t,sep,simple) -- hash only local s = { } - for k, v in next, t do -- indexed? - s[#s+1] = k .. "=" .. tostring(v) + for k, v in sortedhash(t) do + if simple then + if v == true then + s[#s+1] = k + elseif v and v~= "" then + s[#s+1] = k .. "=" .. tostring(v) + end + else + s[#s+1] = k .. "=" .. tostring(v) + end end return concat(s, sep or " | ") end @@ -1593,6 +1632,39 @@ function io.ask(question,default,options) end end +function io.readnumber(f,n,m) + if m then + f:seek("set",n) + n = m + end + if n == 1 then + return byte(f:read(1)) + elseif n == 2 then + local a, b = byte(f:read(2),1,2) + return 256*a + b + elseif n == 4 then + local a, b, c, d = byte(f:read(4),1,4) + return 256^3 * a + 256^2 * b + 256*c + d + elseif n == 8 then + local a, b = readnumber(f,4), readnumber(f,4) + return 256 * b + c + elseif n == 12 then + local a, b, c = readnumber(f,4), readnumber(f,4), readnumber(f,4) + return 256^2 * a + 256 * b + c + else + return 0 + end +end + +function io.readstring(f,n,m) + if m then + f:seek("set",n) + n = m + end + local str = gsub(f:read(n),"%z","") + return str +end + end -- of closure @@ -1658,6 +1730,23 @@ function number.bits(n,zero) end +function number.bit(p) + return 2 ^ (p - 1) -- 1-based indexing +end + +function number.hasbit(x, p) -- typical call: if hasbit(x, bit(3)) then ... + return x % (p + p) >= p +end + +function number.setbit(x, p) + return hasbit(x, p) and x or x + p +end + +function number.clearbit(x, p) + return hasbit(x, p) and x - p or x +end + + end -- of closure do -- create closure to overcome 200 locals limit @@ -3023,7 +3112,7 @@ end utf = utf or unicode.utf8 local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub -local char, byte, find, bytepairs = string.char, string.byte, string.find, string.bytepairs +local char, byte, find, bytepairs, utfvalues, format = string.char, string.byte, string.find, string.bytepairs, string.utfvalues, string.format -- 0 EF BB BF UTF-8 -- 1 FF FE UTF-16-little-endian @@ -3189,6 +3278,15 @@ function unicode.utf8_to_utf16(str,littleendian) end end +function unicode.utfcodes(str) + local t = { } + for k,v in string.utfvalues(str) do + t[#t+1] = format("0x%04X",k) + end + return concat(t,separator or " ") +end + + end -- of closure @@ -3568,14 +3666,24 @@ function aux.array_to_string(a,separator) end end -function aux.settings_to_set(str,t) +function aux.settings_to_set(str,t) -- tohash? t = t or { } - for s in gmatch(str,"%s*([^,]+)") do + for s in gmatch(str,"%s*([^, ]+)") do -- space added t[s] = true end return t end +function aux.simple_hash_to_string(h, separator) + local t = { } + for k, v in table.sortedhash(h) do + if v then + t[#t+1] = k + end + end + return concat(t,separator or ",") +end + local value = lbrace * lpeg.C((nobrace + nested)^0) * rbrace local pattern = lpeg.Ct((space + value)^0) @@ -3637,6 +3745,60 @@ end -- as we use this a lot ... +function aux.formatcolumns(result,between) + if result and #result > 0 then + between = between or " " + local widths, numbers = { }, { } + local first = result[1] + local n = #first + for i=1,n do + widths[i] = 0 + end + for i=1,#result do + local r = result[i] + for j=1,n do + local rj = r[j] + local tj = type(rj) + if tj == "number" then + numbers[j] = true + end + if tj ~= "string" then + rj = tostring(rj) + r[j] = rj + end + local w = #rj + if w > widths[j] then + widths[j] = w + end + end + end + for i=1,n do + local w = widths[i] + if numbers[i] then + if w > 80 then + widths[i] = "%s" .. between + else + widths[i] = "%0" .. w .. "i" .. between + end + else + if w > 80 then + widths[i] = "%s" .. between + elseif w > 0 then + widths[i] = "%-" .. w .. "s" .. between + else + widths[i] = "%s" + end + end + end + local template = string.strip(concat(widths)) + for i=1,#result do + local str = format(template,unpack(result[i])) + result[i] = string.strip(str) + end + end + return result +end + end -- of closure @@ -3843,7 +4005,7 @@ if not modules then modules = { } end modules ['trac-set'] = { local type, next, tostring = type, next, tostring local concat = table.concat -local format, find, lower, gsub = string.format, string.find, string.lower, string.gsub +local format, find, lower, gsub, simpleesc = string.format, string.find, string.lower, string.gsub, string.simpleesc local is_boolean = string.is_boolean setters = { } @@ -3915,7 +4077,7 @@ local function set(t,what,newvalue) for name, functions in next, data do if done[name] then -- prevent recursion due to wildcards - elseif find(name,w) then + elseif find(name,simpleesc(w)) then done[name] = true for i=1,#functions do functions[i](value) @@ -3979,14 +4141,14 @@ end function setters.enable(t,what) local e = t.enable t.enable, t.done = enable, { } - enable(t,string.simpleesc(tostring(what))) + enable(t,what) t.enable, t.done = e, { } end function setters.disable(t,what) local e = t.disable t.disable, t.done = disable, { } - disable(t,string.simpleesc(tostring(what))) + disable(t,what) t.disable, t.done = e, { } end @@ -4050,36 +4212,50 @@ trackers = setters.new("trackers") directives = setters.new("directives") experiments = setters.new("experiments") +-- experiment + +if trackers and environment and environment.engineflags.trackers then + trackers.enable(environment.engineflags.trackers) +end +if directives and environment and environment.engineflags.directives then + directives.enable(environment.engineflags.directives) +end + -- nice trick: we overload two of the directives related functions with variants that -- do tracing (itself using a tracker) .. proof of concept +local function report(...) -- messy .. chicken or egg + local p = (commands and commands.writestatus) or (logs and logs.report) + if p then p(...) end +end + local trace_directives = false local trace_directives = false trackers.register("system.directives", function(v) trace_directives = v end) local trace_experiments = false local trace_experiments = false trackers.register("system.experiments", function(v) trace_experiments = v end) -local e = directives.enable -local d = directives.disable +local enable = directives.enable +local disable = directives.disable function directives.enable(...) - (commands.writestatus or logs.report)("directives","enabling: %s",concat({...}," ")) - e(...) + report("directives","enabling: %s",concat({...}," ")) + enable(...) end function directives.disable(...) - (commands.writestatus or logs.report)("directives","disabling: %s",concat({...}," ")) - d(...) + report("directives","disabling: %s",concat({...}," ")) + disable(...) end -local e = experiments.enable -local d = experiments.disable +local enable = experiments.enable +local disable = experiments.disable function experiments.enable(...) - (commands.writestatus or logs.report)("experiments","enabling: %s",concat({...}," ")) - e(...) + report("experiments","enabling: %s",concat({...}," ")) + enable(...) end function experiments.disable(...) - (commands.writestatus or logs.report)("experiments","disabling: %s",concat({...}," ")) - d(...) + report("experiments","disabling: %s",concat({...}," ")) + disable(...) end -- a useful example @@ -4088,6 +4264,15 @@ directives.register("system.nostatistics", function(v) statistics.enable = not v end) +-- experiment + +if trackers and environment and environment.engineflags.trackers then + trackers.enable(environment.engineflags.trackers) +end +if directives and environment and environment.engineflags.directives then + directives.enable(environment.engineflags.directives) +end + end -- of closure @@ -6357,17 +6542,19 @@ apply_axis['child'] = function(list) for l=1,#list do local ll = list[l] local dt = ll.dt - local en = 0 - for k=1,#dt do - local dk = dt[k] - if dk.tg then - collected[#collected+1] = dk - dk.ni = k -- refresh - en = en + 1 - dk.ei = en + if dt then -- weird that this is needed + local en = 0 + for k=1,#dt do + local dk = dt[k] + if dk.tg then + collected[#collected+1] = dk + dk.ni = k -- refresh + en = en + 1 + dk.ei = en + end end + ll.en = en end - ll.en = en end return collected end @@ -8079,6 +8266,7 @@ local finalizers = xml.finalizers.xml local xmlfilter = xml.filter -- we could inline this one for speed local xmltostring = xml.tostring local xmlserialize = xml.serialize +local xmlcollected = xml.collected local function first(collected) -- wrong ? return collected and collected[1] @@ -8356,6 +8544,19 @@ xml.all = xml.filter xml.index = xml.position xml.found = xml.filter +-- a nice one: + +local function totable(x) + local t = { } + for e in xmlcollected(x[1] or x,"/*") do + t[e.tg] = xmltostring(e.dt) or "" + end + return next(t) and t or nil +end + +xml.table = totable +finalizers.table = totable + end -- of closure @@ -8943,6 +9144,7 @@ formats['pfb'] = 'T1FONTS' suffixes['pfb'] = { 'pfb', ' formats['vf'] = 'VFFONTS' suffixes['vf'] = { 'vf' } formats['fea'] = 'FONTFEATURES' suffixes['fea'] = { 'fea' } formats['cid'] = 'FONTCIDMAPS' suffixes['cid'] = { 'cid', 'cidmap' } +formats['icc'] = 'ICCPROFILES' suffixes['icc'] = { 'icc' } formats['texmfscripts'] = 'TEXMFSCRIPTS' suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } formats['lua'] = 'LUAINPUTS' suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' } formats['lib'] = 'CLUAINPUTS' suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' } @@ -8958,6 +9160,7 @@ alternatives['truetype fonts'] = 'ttf' alternatives['truetype collections'] = 'ttc' alternatives['truetype dictionary'] = 'dfont' alternatives['type1 fonts'] = 'pfb' +alternatives['icc profiles'] = 'icc' --[[ldx-- <p>If you wondered about some of the previous mappings, how about @@ -12160,6 +12363,21 @@ if not modules then modules = { } end modules ['luat-fmt'] = { -- helper for mtxrun +local quote = string.quote + +local function primaryflags() + local trackers = environment.argument("trackers") + local directives = environment.argument("directives") + local flags = "" + if trackers and trackers ~= "" then + flags = flags .. "--trackers=" .. quote(trackers) + end + if directives and directives ~= "" then + flags = flags .. "--directives=" .. quote(directives) + end + return flags +end + function environment.make_format(name) -- change to format path (early as we need expanded paths) local olddir = lfs.currentdir() @@ -12220,8 +12438,7 @@ function environment.make_format(name) return end -- generate format - local q = string.quote - local command = string.format("luatex --ini --lua=%s %s %sdump",q(usedluastub),q(fulltexsourcename),os.platform == "unix" and "\\\\" or "\\") + local command = string.format("luatex --ini %s --lua=%s %s %sdump",primaryflags(),quote(usedluastub),quote(fulltexsourcename),os.platform == "unix" and "\\\\" or "\\") logs.simple("running command: %s\n",command) os.spawn(command) -- remove related mem files @@ -12260,7 +12477,7 @@ function environment.run_format(name,data,more) logs.simple("no luc/lua with name: %s",barename) else local q = string.quote - local command = string.format("luatex --fmt=%s --lua=%s %s %s",q(barename),q(luaname),q(data),more ~= "" and q(more) or "") + local command = string.format("luatex %s --fmt=%s --lua=%s %s %s",primaryflags(),quote(barename),quote(luaname),quote(data),more ~= "" and quote(more) or "") logs.simple("running command: %s",command) os.spawn(command) end diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index ac4b0556e..68ee3d2c1 100755 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -347,7 +347,8 @@ patterns.hexadecimal = P("0x") * R("09","AF","af")^1 patterns.lowercase = R("az") patterns.uppercase = R("AZ") patterns.letter = patterns.lowercase + patterns.uppercase -patterns.space = S(" ") +patterns.space = P(" ") +patterns.tab = P("\t") patterns.eol = S("\n\r") patterns.spacer = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto) patterns.newline = crlf + cr + lf @@ -358,6 +359,9 @@ patterns.nonwhitespace = 1 - patterns.whitespace patterns.utf8 = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four patterns.utfbom = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191') patterns.validutf8 = patterns.utf8^0 * P(-1) * Cc(true) + Cc(false) +patterns.comma = P(",") +patterns.commaspacer = P(",") * patterns.spacer^0 +patterns.period = P(".") patterns.undouble = P('"')/"" * (1-P('"'))^0 * P('"')/"" patterns.unsingle = P("'")/"" * (1-P("'"))^0 * P("'")/"" @@ -462,15 +466,36 @@ local function f4(s) local c1, c2, c3, c4 = f1(s,1,4) return ((c1 * 64 + c2) * 6 patterns.utf8byte = patterns.utf8one/f1 + patterns.utf8two/f2 + patterns.utf8three/f3 + patterns.utf8four/f4 + + local cache = { } function lpeg.stripper(str) - local s = cache[str] - if not s then - s = Cs(((S(str)^1)/"" + 1)^0) - cache[str] = s + if type(str) == "string" then + local s = cache[str] + if not s then + s = Cs(((S(str)^1)/"" + 1)^0) + cache[str] = s + end + return s + else + return Cs(((str^1)/"" + 1)^0) + end +end + +local cache = { } + +function lpeg.keeper(str) + if type(str) == "string" then + local s = cache[str] + if not s then + s = Cs((((1-S(str))^1)/"" + 1)^0) + cache[str] = s + end + return s + else + return Cs((((1-str)^1)/"" + 1)^0) end - return s end function lpeg.replacer(t) @@ -642,7 +667,7 @@ end table.sortedkeys = sortedkeys table.sortedhashkeys = sortedhashkeys -function table.sortedhash(t) +local function sortedhash(t) local s = sortedhashkeys(t) -- maybe just sortedkeys local n = 0 local function kv(s) @@ -653,7 +678,8 @@ function table.sortedhash(t) return kv, s end -table.sortedpairs = table.sortedhash +table.sortedhash = sortedhash +table.sortedpairs = sortedhash function table.append(t, list) for _,v in next, list do @@ -1315,12 +1341,17 @@ function table.count(t) return n end -function table.swapped(t) - local s = { } +function table.swapped(t,s) + local n = { } + if s then + for k, v in next, s do + n[k] = v + end + end for k, v in next, t do - s[v] = k + n[v] = k end - return s + return n end @@ -1340,7 +1371,7 @@ function table.hexed(t,seperator) return concat(tt,seperator or " ") end -function table.reverse_hash(h) +function table.reverse_hash(h) -- needs another name local r = { } for k,v in next, h do r[v] = lower(gsub(k," ","")) @@ -1388,10 +1419,18 @@ function table.insert_after_value(t,value,extra) insert(t,#t+1,extra) end -function table.sequenced(t,sep) +function table.sequenced(t,sep,simple) -- hash only local s = { } - for k, v in next, t do -- indexed? - s[#s+1] = k .. "=" .. tostring(v) + for k, v in sortedhash(t) do + if simple then + if v == true then + s[#s+1] = k + elseif v and v~= "" then + s[#s+1] = k .. "=" .. tostring(v) + end + else + s[#s+1] = k .. "=" .. tostring(v) + end end return concat(s, sep or " | ") end @@ -1593,6 +1632,39 @@ function io.ask(question,default,options) end end +function io.readnumber(f,n,m) + if m then + f:seek("set",n) + n = m + end + if n == 1 then + return byte(f:read(1)) + elseif n == 2 then + local a, b = byte(f:read(2),1,2) + return 256*a + b + elseif n == 4 then + local a, b, c, d = byte(f:read(4),1,4) + return 256^3 * a + 256^2 * b + 256*c + d + elseif n == 8 then + local a, b = readnumber(f,4), readnumber(f,4) + return 256 * b + c + elseif n == 12 then + local a, b, c = readnumber(f,4), readnumber(f,4), readnumber(f,4) + return 256^2 * a + 256 * b + c + else + return 0 + end +end + +function io.readstring(f,n,m) + if m then + f:seek("set",n) + n = m + end + local str = gsub(f:read(n),"%z","") + return str +end + end -- of closure @@ -1658,6 +1730,23 @@ function number.bits(n,zero) end +function number.bit(p) + return 2 ^ (p - 1) -- 1-based indexing +end + +function number.hasbit(x, p) -- typical call: if hasbit(x, bit(3)) then ... + return x % (p + p) >= p +end + +function number.setbit(x, p) + return hasbit(x, p) and x or x + p +end + +function number.clearbit(x, p) + return hasbit(x, p) and x - p or x +end + + end -- of closure do -- create closure to overcome 200 locals limit @@ -3023,7 +3112,7 @@ end utf = utf or unicode.utf8 local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub -local char, byte, find, bytepairs = string.char, string.byte, string.find, string.bytepairs +local char, byte, find, bytepairs, utfvalues, format = string.char, string.byte, string.find, string.bytepairs, string.utfvalues, string.format -- 0 EF BB BF UTF-8 -- 1 FF FE UTF-16-little-endian @@ -3189,6 +3278,15 @@ function unicode.utf8_to_utf16(str,littleendian) end end +function unicode.utfcodes(str) + local t = { } + for k,v in string.utfvalues(str) do + t[#t+1] = format("0x%04X",k) + end + return concat(t,separator or " ") +end + + end -- of closure @@ -3568,14 +3666,24 @@ function aux.array_to_string(a,separator) end end -function aux.settings_to_set(str,t) +function aux.settings_to_set(str,t) -- tohash? t = t or { } - for s in gmatch(str,"%s*([^,]+)") do + for s in gmatch(str,"%s*([^, ]+)") do -- space added t[s] = true end return t end +function aux.simple_hash_to_string(h, separator) + local t = { } + for k, v in table.sortedhash(h) do + if v then + t[#t+1] = k + end + end + return concat(t,separator or ",") +end + local value = lbrace * lpeg.C((nobrace + nested)^0) * rbrace local pattern = lpeg.Ct((space + value)^0) @@ -3637,6 +3745,60 @@ end -- as we use this a lot ... +function aux.formatcolumns(result,between) + if result and #result > 0 then + between = between or " " + local widths, numbers = { }, { } + local first = result[1] + local n = #first + for i=1,n do + widths[i] = 0 + end + for i=1,#result do + local r = result[i] + for j=1,n do + local rj = r[j] + local tj = type(rj) + if tj == "number" then + numbers[j] = true + end + if tj ~= "string" then + rj = tostring(rj) + r[j] = rj + end + local w = #rj + if w > widths[j] then + widths[j] = w + end + end + end + for i=1,n do + local w = widths[i] + if numbers[i] then + if w > 80 then + widths[i] = "%s" .. between + else + widths[i] = "%0" .. w .. "i" .. between + end + else + if w > 80 then + widths[i] = "%s" .. between + elseif w > 0 then + widths[i] = "%-" .. w .. "s" .. between + else + widths[i] = "%s" + end + end + end + local template = string.strip(concat(widths)) + for i=1,#result do + local str = format(template,unpack(result[i])) + result[i] = string.strip(str) + end + end + return result +end + end -- of closure @@ -3843,7 +4005,7 @@ if not modules then modules = { } end modules ['trac-set'] = { local type, next, tostring = type, next, tostring local concat = table.concat -local format, find, lower, gsub = string.format, string.find, string.lower, string.gsub +local format, find, lower, gsub, simpleesc = string.format, string.find, string.lower, string.gsub, string.simpleesc local is_boolean = string.is_boolean setters = { } @@ -3915,7 +4077,7 @@ local function set(t,what,newvalue) for name, functions in next, data do if done[name] then -- prevent recursion due to wildcards - elseif find(name,w) then + elseif find(name,simpleesc(w)) then done[name] = true for i=1,#functions do functions[i](value) @@ -3979,14 +4141,14 @@ end function setters.enable(t,what) local e = t.enable t.enable, t.done = enable, { } - enable(t,string.simpleesc(tostring(what))) + enable(t,what) t.enable, t.done = e, { } end function setters.disable(t,what) local e = t.disable t.disable, t.done = disable, { } - disable(t,string.simpleesc(tostring(what))) + disable(t,what) t.disable, t.done = e, { } end @@ -4050,36 +4212,50 @@ trackers = setters.new("trackers") directives = setters.new("directives") experiments = setters.new("experiments") +-- experiment + +if trackers and environment and environment.engineflags.trackers then + trackers.enable(environment.engineflags.trackers) +end +if directives and environment and environment.engineflags.directives then + directives.enable(environment.engineflags.directives) +end + -- nice trick: we overload two of the directives related functions with variants that -- do tracing (itself using a tracker) .. proof of concept +local function report(...) -- messy .. chicken or egg + local p = (commands and commands.writestatus) or (logs and logs.report) + if p then p(...) end +end + local trace_directives = false local trace_directives = false trackers.register("system.directives", function(v) trace_directives = v end) local trace_experiments = false local trace_experiments = false trackers.register("system.experiments", function(v) trace_experiments = v end) -local e = directives.enable -local d = directives.disable +local enable = directives.enable +local disable = directives.disable function directives.enable(...) - (commands.writestatus or logs.report)("directives","enabling: %s",concat({...}," ")) - e(...) + report("directives","enabling: %s",concat({...}," ")) + enable(...) end function directives.disable(...) - (commands.writestatus or logs.report)("directives","disabling: %s",concat({...}," ")) - d(...) + report("directives","disabling: %s",concat({...}," ")) + disable(...) end -local e = experiments.enable -local d = experiments.disable +local enable = experiments.enable +local disable = experiments.disable function experiments.enable(...) - (commands.writestatus or logs.report)("experiments","enabling: %s",concat({...}," ")) - e(...) + report("experiments","enabling: %s",concat({...}," ")) + enable(...) end function experiments.disable(...) - (commands.writestatus or logs.report)("experiments","disabling: %s",concat({...}," ")) - d(...) + report("experiments","disabling: %s",concat({...}," ")) + disable(...) end -- a useful example @@ -4088,6 +4264,15 @@ directives.register("system.nostatistics", function(v) statistics.enable = not v end) +-- experiment + +if trackers and environment and environment.engineflags.trackers then + trackers.enable(environment.engineflags.trackers) +end +if directives and environment and environment.engineflags.directives then + directives.enable(environment.engineflags.directives) +end + end -- of closure @@ -6357,17 +6542,19 @@ apply_axis['child'] = function(list) for l=1,#list do local ll = list[l] local dt = ll.dt - local en = 0 - for k=1,#dt do - local dk = dt[k] - if dk.tg then - collected[#collected+1] = dk - dk.ni = k -- refresh - en = en + 1 - dk.ei = en + if dt then -- weird that this is needed + local en = 0 + for k=1,#dt do + local dk = dt[k] + if dk.tg then + collected[#collected+1] = dk + dk.ni = k -- refresh + en = en + 1 + dk.ei = en + end end + ll.en = en end - ll.en = en end return collected end @@ -8079,6 +8266,7 @@ local finalizers = xml.finalizers.xml local xmlfilter = xml.filter -- we could inline this one for speed local xmltostring = xml.tostring local xmlserialize = xml.serialize +local xmlcollected = xml.collected local function first(collected) -- wrong ? return collected and collected[1] @@ -8356,6 +8544,19 @@ xml.all = xml.filter xml.index = xml.position xml.found = xml.filter +-- a nice one: + +local function totable(x) + local t = { } + for e in xmlcollected(x[1] or x,"/*") do + t[e.tg] = xmltostring(e.dt) or "" + end + return next(t) and t or nil +end + +xml.table = totable +finalizers.table = totable + end -- of closure @@ -8943,6 +9144,7 @@ formats['pfb'] = 'T1FONTS' suffixes['pfb'] = { 'pfb', ' formats['vf'] = 'VFFONTS' suffixes['vf'] = { 'vf' } formats['fea'] = 'FONTFEATURES' suffixes['fea'] = { 'fea' } formats['cid'] = 'FONTCIDMAPS' suffixes['cid'] = { 'cid', 'cidmap' } +formats['icc'] = 'ICCPROFILES' suffixes['icc'] = { 'icc' } formats['texmfscripts'] = 'TEXMFSCRIPTS' suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } formats['lua'] = 'LUAINPUTS' suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' } formats['lib'] = 'CLUAINPUTS' suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' } @@ -8958,6 +9160,7 @@ alternatives['truetype fonts'] = 'ttf' alternatives['truetype collections'] = 'ttc' alternatives['truetype dictionary'] = 'dfont' alternatives['type1 fonts'] = 'pfb' +alternatives['icc profiles'] = 'icc' --[[ldx-- <p>If you wondered about some of the previous mappings, how about @@ -12160,6 +12363,21 @@ if not modules then modules = { } end modules ['luat-fmt'] = { -- helper for mtxrun +local quote = string.quote + +local function primaryflags() + local trackers = environment.argument("trackers") + local directives = environment.argument("directives") + local flags = "" + if trackers and trackers ~= "" then + flags = flags .. "--trackers=" .. quote(trackers) + end + if directives and directives ~= "" then + flags = flags .. "--directives=" .. quote(directives) + end + return flags +end + function environment.make_format(name) -- change to format path (early as we need expanded paths) local olddir = lfs.currentdir() @@ -12220,8 +12438,7 @@ function environment.make_format(name) return end -- generate format - local q = string.quote - local command = string.format("luatex --ini --lua=%s %s %sdump",q(usedluastub),q(fulltexsourcename),os.platform == "unix" and "\\\\" or "\\") + local command = string.format("luatex --ini %s --lua=%s %s %sdump",primaryflags(),quote(usedluastub),quote(fulltexsourcename),os.platform == "unix" and "\\\\" or "\\") logs.simple("running command: %s\n",command) os.spawn(command) -- remove related mem files @@ -12260,7 +12477,7 @@ function environment.run_format(name,data,more) logs.simple("no luc/lua with name: %s",barename) else local q = string.quote - local command = string.format("luatex --fmt=%s --lua=%s %s %s",q(barename),q(luaname),q(data),more ~= "" and q(more) or "") + local command = string.format("luatex %s --fmt=%s --lua=%s %s %s",primaryflags(),quote(barename),quote(luaname),quote(data),more ~= "" and quote(more) or "") logs.simple("running command: %s",command) os.spawn(command) end |