diff options
48 files changed, 4612 insertions, 1952 deletions
diff --git a/scripts/context/lua/luatools.lua b/scripts/context/lua/luatools.lua index b092c5050..89e5e0eb4 100644 --- a/scripts/context/lua/luatools.lua +++ b/scripts/context/lua/luatools.lua @@ -15,7 +15,7 @@ -- the future. As long as Luatex is under development the -- interfaces and names of functions may change. -banner = "version 1.1.1 - 2006+ - PRAGMA ADE / CONTEXT" +banner = "version 1.2.0 - 2006+ - PRAGMA ADE / CONTEXT" texlua = true -- For the sake of independence we optionally can merge the library @@ -374,7 +374,6 @@ local patterns_escapes = { ["]"] = "%]", } - function string:pattesc() return (self:gsub(".",patterns_escapes)) end @@ -1687,14 +1686,22 @@ end --~ print("../test/" .. " == " .. file.collapse_path("../test/")) --~ print("a/a" .. " == " .. file.collapse_path("a/b/c/../../a")) +--~ function file.collapse_path(str) +--~ local ok, n = false, 0 +--~ while not ok do +--~ ok = true +--~ str, n = str:gsub("[^%./]+/%.%./", function(s) +--~ ok = false +--~ return "" +--~ end) +--~ end +--~ return (str:gsub("/%./","/")) +--~ end + function file.collapse_path(str) - local ok, n = false, 0 - while not ok do - ok = true - str, n = str:gsub("[^%./]+/%.%./", function(s) - ok = false - return "" - end) + local n = 1 + while n > 0 do + str, n = str:gsub("([^/%.]+/%.%./)","") end return (str:gsub("/%./","/")) end @@ -1762,7 +1769,7 @@ function url.hashed(str) path = s[3], query = s[4], fragment = s[5], - original=str + original = str } end @@ -2560,14 +2567,32 @@ os.platform = os.platform or os.type or (io.pathseparator == ";" and "windows") -- -- for k,v in pairs(arg) do print(k,v) end -if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then - arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil -end - -- environment if not environment then environment = { } end +environment.ownbin = environment.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex" + +local ownpath = nil -- we could use a metatable here + +function environment.ownpath() + if not ownpath then + for p in string.gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do + local b = file.join(p,environment.ownbin) + if lfs.isfile(b..".exe") or lfs.isfile(b) then + ownpath = p + break + end + end + if not ownpath then ownpath = '.' end + end + return ownpath +end + +if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then + arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil +end + environment.arguments = { } environment.files = { } environment.sorted_argument_keys = nil @@ -2679,6 +2704,10 @@ end -- additional functionality becomes available. We will split this -- module in components when we're done with prototyping. +-- TODO: os.getenv -> os.env[] +-- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller) +-- TODO: check escaping in find etc, too much, too slow + -- This is the first code I wrote for LuaTeX, so it needs some cleanup. -- To be considered: hash key lowercase, first entry in table filename @@ -2689,9 +2718,6 @@ end -- Beware, loading and saving is overloaded in luat-tmp! --- todo: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller) --- todo: check escaping in find etc, too much, too slow - if not versions then versions = { } end versions['luat-inp'] = 1.001 if not environment then environment = { } end if not file then file = { } end @@ -2710,6 +2736,8 @@ if not input.hashers then input.hashers = { } end -- load databases if not input.generators then input.generators = { } end -- generate databases if not input.filters then input.filters = { } end -- conversion filters +local format = string.format + input.locators.notfound = { nil } input.hashers.notfound = { nil } input.generators.notfound = { nil } @@ -2719,6 +2747,7 @@ input.banner = nil input.verbose = false input.debug = false input.cnfname = 'texmf.cnf' +input.luaname = 'texmfcnf.lua' input.lsrname = 'ls-R' input.luasuffix = '.tma' input.lucsuffix = '.tmc' @@ -2808,12 +2837,14 @@ function input.reset() instance.files = { } instance.remap = { } instance.configuration = { } + instance.setup = { } instance.order = { } instance.found = { } instance.foundintrees = { } instance.kpsevars = { } instance.hashes = { } instance.cnffiles = { } + instance.luafiles = { } instance.lists = { } instance.remember = true instance.diskcache = true @@ -2833,7 +2864,6 @@ function input.reset() instance.stoptime = 0 instance.validfile = function(path,name) return true end instance.data = { } -- only for loading - instance.sortdata = false instance.force_suffixes = true instance.dummy_path_expr = "^!*unset/*$" instance.fakepaths = { } @@ -2846,7 +2876,7 @@ function input.reset() end else -- we will access os.env frequently - for k,v in pairs({'HOME','TEXMF','TEXMFCNF','SELFAUTOPARENT'}) do + for k,v in pairs({'HOME','TEXMF','TEXMFCNF'}) do local e = os.getenv(v) if e then -- input.report("setting",v,"to",input.bare_variable(e)) @@ -2874,7 +2904,7 @@ function input.reset_hashes(instance) instance.found = { } end -function input.bare_variable(str) +function input.bare_variable(str) -- assumes str is a string -- return string.gsub(string.gsub(string.gsub(str,"%s+$",""),'^"(.+)"$',"%1"),"^'(.+)'$","%1") return (str:gsub("\s*([\"\']?)(.+)%1\s*", "%2")) end @@ -2959,7 +2989,7 @@ do instance.stoptime = stoptime instance.loadtime = instance.loadtime + loadtime if report then - input.report('load time', string.format("%0.3f",loadtime)) + input.report('load time', format("%0.3f",loadtime)) end return loadtime end @@ -2970,7 +3000,7 @@ do end function input.elapsedtime(instance) - return string.format("%0.3f",(instance and instance.loadtime) or 0) + return format("%0.3f",(instance and instance.loadtime) or 0) end function input.report_loadtime(instance) @@ -2986,15 +3016,19 @@ function input.env(instance,key) end function input.osenv(instance,key) - if instance.environment[key] == nil then - local e = os.getenv(key) + local ie = instance.environment + local value = ie[key] + if value == nil then + -- local e = os.getenv(key) + local e = os.env[key] if e == nil then - instance.environment[key] = "" -- false + -- value = "" -- false else - instance.environment[key] = input.bare_variable(e) + value = input.bare_variable(e) end + ie[key] = value end - return instance.environment[key] or "" + return value or "" end -- we follow a rather traditional approach: @@ -3005,66 +3039,103 @@ end -- for the moment we don't expect a configuration file in a zip function input.identify_cnf(instance) + -- we no longer support treepath and rootpath (was handy for testing); + -- also we now follow the stupid route: if not set then just assume *one* + -- cnf file under texmf (i.e. distribution) if #instance.cnffiles == 0 then - if instance.treepath ~= "" then - -- this is a special purpose branch, not really used - if instance.rootpath ~= "" then - local t = instance.treepath:splitchr(',') - for k,v in ipairs(t) do - t[k] = file.join(instance.rootpath,v) + if input.env(instance,'TEXMFCNF') == "" then + local ownpath = environment.ownpath() or "." + if ownpath then + -- beware, this is tricky on my own system because at that location I do have + -- the raw tree that ends up in the zip; i.e. I cannot test this kind of mess + local function locate(filename,list) + local ownroot = input.normalize_name(file.join(ownpath,"../..")) + if not lfs.isdir(file.join(ownroot,"texmf")) then + ownroot = input.normalize_name(file.join(ownpath,"..")) + if not lfs.isdir(file.join(ownroot,"texmf")) then + input.verbose = true + input.report("error", "unable to identify cnf file") + return + end + end + local texmfcnf = file.join(ownroot,"texmf-local/web2c",filename) -- for minimals and myself + if not lfs.isfile(texmfcnf) then + texmfcnf = file.join(ownroot,"texmf/web2c",filename) + if not lfs.isfile(texmfcnf) then + input.verbose = true + input.report("error", "unable to locate",filename) + return + end + end + table.insert(list,texmfcnf) + local ie = instance.environment + if not ie['SELFAUTOPARENT'] then ie['SELFAUTOPARENT'] = ownroot end + if not ie['TEXMFCNF'] then ie['TEXMFCNF'] = file.dirname(texmfcnf) end + end + locate(input.luaname,instance.luafiles) + locate(input.cnfname,instance.cnffiles) + if #instance.luafiles == 0 and instance.cnffiles == 0 then + input.verbose = true + input.report("error", "unable to locate",filename) + os.exit() end - instance.treepath = table.concat(t,',') + -- here we also assume then TEXMF is set in the distribution, if this trickery is + -- used in the minimals, then users who don't use setuptex are on their own with + -- regards to extra trees + else + input.verbose = true + input.report("error", "unable to identify own path") + os.exit() end - local t = instance.treepath:splitchr(',') - instance.environment['TEXMF'] = input.bare_variable(instance.treepath) - instance.environment['TEXMFCNF'] = file.join(t[1] or '.','texmf/web2c') - end - if instance.rootpath ~= "" then - -- this assumes a single path, maybe do an expanded split here too - instance.environment['TEXMFCNF'] = file.join(instance.rootpath,'texmf/web2c') - instance.environment['SELFAUTOPARENT'] = instance.rootpath - end - if input.env(instance,'TEXMFCNF') ~= "" then + else local t = input.split_path(input.env(instance,'TEXMFCNF')) t = input.aux.expanded_path(instance,t) input.aux.expand_vars(instance,t) - for _,v in ipairs(t) do - table.insert(instance.cnffiles,file.join(v,input.cnfname)) - end - elseif input.env(instance,'SELFAUTOPARENT') == '.' then - table.insert(instance.cnffiles,file.join('.',input.cnfname)) - else - for _,v in ipairs({'texmf-local','texmf'}) do - table.insert(instance.cnffiles,file.join(input.env(instance,'SELFAUTOPARENT'),v,'web2c',input.cnfname)) + local function locate(filename,list) + for _,v in ipairs(t) do + local texmfcnf = input.normalize_name(file.join(v,filename)) + if lfs.isfile(texmfcnf) then + table.insert(list,texmfcnf) + end + end end + locate(input.luaname,instance.luafiles) + locate(input.cnfname,instance.cnffiles) end end end function input.load_cnf(instance) + local function loadoldconfigdata() + for _, fname in ipairs(instance.cnffiles) do + input.aux.load_cnf(instance,fname) + end + end -- instance.cnffiles contain complete names now ! if #instance.cnffiles == 0 then input.report("no cnf files found (TEXMFCNF may not be set/known)") else instance.rootpath = instance.cnffiles[1] for k,fname in ipairs(instance.cnffiles) do - instance.cnffiles[k] = fname:gsub("\\",'/') -- needed? + instance.cnffiles[k] = input.normalize_name(fname:gsub("\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end + instance.rootpath = input.normalize_name(instance.rootpath) + instance.environment['SELFAUTOPARENT'] = instance.rootpath -- just to be sure if instance.lsrmode then - input.loadconfigdata(instance,instance.cnffiles) + loadoldconfigdata() elseif instance.diskcache and not instance.renewcache then - input.loadconfig(instance,instance.cnffiles) + input.loadoldconfig(instance,instance.cnffiles) if instance.loaderror then - input.loadconfigdata(instance,instance.cnffiles) - input.saveconfig(instance) + loadoldconfigdata() + input.saveoldconfig(instance) end else - input.loadconfigdata(instance,instance.cnffiles) + loadoldconfigdata() if instance.renewcache then - input.saveconfig(instance) + input.saveoldconfig(instance) end end input.aux.collapse_cnf_data(instance) @@ -3072,40 +3143,34 @@ function input.load_cnf(instance) input.checkconfigdata(instance) end -function input.loadconfigdata(instance) - for _, fname in ipairs(instance.cnffiles) do - input.aux.load_cnf(instance,fname) +function input.load_lua(instance) + if #instance.luafiles == 0 then + -- yet harmless + else + instance.rootpath = instance.luafiles[1] + for k,fname in ipairs(instance.luafiles) do + instance.luafiles[k] = input.normalize_name(fname:gsub("\\",'/')) + end + for i=1,3 do + instance.rootpath = file.dirname(instance.rootpath) + end + instance.rootpath = input.normalize_name(instance.rootpath) + instance.environment['SELFAUTOPARENT'] = instance.rootpath -- just to be sure + input.loadnewconfig(instance) + input.aux.collapse_cnf_data(instance) end + input.checkconfigdata(instance) end -if os.env then - function input.aux.collapse_cnf_data(instance) - for _,c in ipairs(instance.order) do - for k,v in pairs(c) do - if not instance.variables[k] then - if instance.environment[k] then - instance.variables[k] = instance.environment[k] - else - instance.kpsevars[k] = true - instance.variables[k] = input.bare_variable(v) - end - end - end - end - end -else - function input.aux.collapse_cnf_data(instance) - for _,c in ipairs(instance.order) do - for k,v in pairs(c) do - if not instance.variables[k] then - local e = os.getenv(k) - if e then - instance.environment[k] = input.bare_variable(e) - instance.variables[k] = instance.environment[k] - else - instance.variables[k] = input.bare_variable(v) - instance.kpsevars[k] = true - end +function input.aux.collapse_cnf_data(instance) -- potential optmization: pass start index (setup and configuration are shared) + for _,c in ipairs(instance.order) do + for k,v in pairs(c) do + if not instance.variables[k] then + if instance.environment[k] then + instance.variables[k] = instance.environment[k] + else + instance.kpsevars[k] = true + instance.variables[k] = input.bare_variable(v) end end end @@ -3116,11 +3181,11 @@ function input.aux.load_cnf(instance,fname) fname = input.clean_path(fname) local lname = fname:gsub("%.%a+$",input.luasuffix) local f = io.open(lname) - if f then + if f then -- this will go f:close() local dname = file.dirname(fname) if not instance.configuration[dname] then - input.aux.load_data(instance,dname,'configuration',file.basename(lname)) + input.aux.load_configuration(instance,dname,lname) instance.order[#instance.order+1] = instance.configuration[dname] end else @@ -3135,7 +3200,7 @@ function input.aux.load_cnf(instance,fname) end local data = instance.configuration[dname] while true do - line = f:read() + local line, n = f:read(), 0 if line then while true do -- join lines line, n = line:gsub("\\%s*$", "") @@ -3146,7 +3211,7 @@ function input.aux.load_cnf(instance,fname) end end if not line:find("^[%%#]") then - k, v = (line:gsub("%s*%%.*$","")):match("%s*(.-)%s*=%s*(.-)%s*$") + local k, v = (line:gsub("%s*%%.*$","")):match("%s*(.-)%s*=%s*(.-)%s*$") if k and v and not data[k] then data[k] = (v:gsub("[%%#].*",'')):gsub("~", "$HOME") instance.kpsevars[k] = true @@ -3220,6 +3285,7 @@ end function input.locatelists(instance) for _, path in pairs(input.simplified_list(input.expansion(instance,'TEXMF'))) do + path = file.collapse_path(path) input.report("locating list of",path) input.locatedatabase(instance,input.normalize_name(path)) end @@ -3256,7 +3322,7 @@ function input.loadfiles(instance) end function input.hashers.tex(instance,tag,name) - input.aux.load_data(instance,tag,'files') + input.aux.load_files(instance,tag) end -- generators: @@ -3333,7 +3399,7 @@ do end end action() - input.report(string.format("%s files found on %s directories with %s uppercase remappings",n,m,r)) + input.report(format("%s files found on %s directories with %s uppercase remappings",n,m,r)) else local fullname = file.join(specification,input.lsrname) local path = '.' @@ -3386,7 +3452,7 @@ end -- is more convenient. function input.splitconfig(instance) - for i,c in ipairs(instance.order) do + for i,c in ipairs(instance) do for k,v in pairs(c) do if type(v) == 'string' then local t = file.split_path(v) @@ -3420,14 +3486,7 @@ function input.join_path(str) return str end end ---~ function input.splitexpansions(instance) ---~ for k,v in pairs(instance.expansions) do ---~ local t = file.split_path(v) ---~ if #t > 1 then ---~ instance.expansions[k] = t ---~ end ---~ end ---~ end + function input.splitexpansions(instance) for k,v in pairs(instance.expansions) do local t, h = { }, { } @@ -3447,7 +3506,7 @@ end -- end of split/join code -function input.saveconfig(instance) +function input.saveoldconfig(instance) input.splitconfig(instance) input.aux.save_data(instance, 'configuration', nil) input.joinconfig(instance) @@ -3460,44 +3519,83 @@ input.configbanner = [[ -- not copyrighted. [HH & TH] ]] -function input.aux.save_data(instance, dataname, check) - for cachename, files in pairs(instance[dataname]) do - local name = file.join(cachename,dataname) - local luaname, lucname = name .. input.luasuffix, name .. input.lucsuffix - local f = io.open(luaname,'w') - if f then - input.report("saving " .. dataname .. " in", luaname) - f:write(input.configbanner) - f:write("\n") - f:write("if not texmf then texmf = { } end\n") - f:write("if not texmf.data then texmf.data = { } end\n") - f:write("\n") - f:write("texmf.data.type = '" .. dataname .. "'\n") - f:write("texmf.data.version = '" .. input.cacheversion .. "'\n") - f:write("texmf.data.date = '" .. os.date("%Y-%m-%d") .. "'\n") - f:write("texmf.data.time = '" .. os.date("%H:%M:%S") .. "'\n") - f:write('texmf.data.content = {\n') - local function dump(k,v) - if not check or check(v,k) then -- path, name - if type(v) == 'string' then - f:write("\t['" .. k .. "'] = '" .. v .. "',\n") - elseif #v == 1 then - f:write("\t['" .. k .. "'] = '" .. v[1] .. "',\n") - else - f:write("\t['" .. k .. "'] = {'" .. table.concat(v,"','").. "'},\n") - end +function input.serialize(files) + -- This version is somewhat optimized for the kind of + -- tables that we deal with, so it's much faster than + -- the generic serializer. This makes sense because + -- luatools and mtxtools are called frequently. Okay, + -- we pay a small price for properly tabbed tables. + local t = { } + local concat = table.concat + local sorted = table.sortedkeys + local function dump(k,v,m) + if type(v) == 'string' then + return m .. "['" .. k .. "']='" .. v .. "'," + elseif #v == 1 then + return m .. "['" .. k .. "']='" .. v[1] .. "'," + else + return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'}," + end + end + t[#t+1] = "return {" + if instance.sortdata then + for _, k in pairs(sorted(files)) do + local fk = files[k] + if type(fk) == 'table' then + t[#t+1] = "\t['" .. k .. "']={" + for _, kk in pairs(sorted(fk)) do + t[#t+1] = dump(kk,fk[kk],"\t\t") end + t[#t+1] = "\t}," + else + t[#t+1] = dump(k,fk,"\t") end - if instance.sortdata then - for _, k in pairs(table.sortedkeys(files)) do - dump(k,files[k]) + end + else + for k, v in pairs(files) do + if type(v) == 'table' then + t[#t+1] = "\t['" .. k .. "']={" + for kk,vv in pairs(v) do + t[#t+1] = dump(kk,vv,"\t\t") end + t[#t+1] = "\t}," else - for k, v in pairs(files) do - dump(k,v) + t[#t+1] = dump(k,v,"\t") + end + end + end + t[#t+1] = "}" + return concat(t,"\n") +end + +if not texmf then texmf = {} end -- no longer needed, at least not here + +function input.aux.save_data(instance, dataname, check, makename) -- untested without cache overload + for cachename, files in pairs(instance[dataname]) do + local name = (makename or file.join)(cachename,dataname) + local luaname, lucname = name .. input.luasuffix, name .. input.lucsuffix + input.report("preparing " .. dataname .. " for", luaname) + for k, v in pairs(files) do + if not check or check(v,k) then -- path, name + if type(v) == "table" and #v == 1 then + files[k] = v[1] end + else + files[k] = nil -- false end - f:write('}\n') + end + local data = { + type = dataname, + root = cachename, + version = input.cacheversion, + date = os.date("%Y-%m-%d"), + time = os.date("%H:%M:%S"), + content = files, + } + local f = io.open(luaname,'w') + if f then + input.report("saving " .. dataname .. " in", luaname) + f:write(input.serialize(data)) f:close() input.report("compiling " .. dataname .. " to", lucname) if not utils.lua.compile(luaname,lucname) then @@ -3510,49 +3608,106 @@ function input.aux.save_data(instance, dataname, check) end end -function input.loadconfig(instance) - instance.configuration, instance.order, instance.loaderror = { }, { }, false - if not instance.renewcache then - for _, cnf in ipairs(instance.cnffiles) do - local dname = file.dirname(cnf) - input.aux.load_data(instance,dname,'configuration') - instance.order[#instance.order+1] = instance.configuration[dname] - if instance.loaderror then break end +function input.aux.load_data(instance,pathname,dataname,filename,makename) -- untested without cache overload + filename = ((not filename or (filename == "")) and dataname) or filename + filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) + local blob = loadfile(filename .. input.lucsuffix) or loadfile(filename .. input.luasuffix) + if blob then + local data = blob() + if data and data.content and data.type == dataname and data.version == input.cacheversion then + input.report("loading",dataname,"for",pathname,"from",filename) + instance[dataname][pathname] = data.content + else + input.report("skipping",dataname,"for",pathname,"from",filename) + instance[dataname][pathname] = { } + instance.loaderror = true end + else + input.report("skipping",dataname,"for",pathname,"from",filename) end - input.joinconfig(instance) end -if not texmf then texmf = {} end -if not texmf.data then texmf.data = {} end +-- some day i'll use the nested approach, but not yet (actually we even drop +-- engine/progname support since we have only luatex now) +-- +-- first texmfcnf.lua files are located, next the cached texmf.cnf files +-- +-- return { +-- TEXMFBOGUS = 'effe checken of dit werkt', +-- } -function input.aux.load_data(instance,pathname,dataname,filename) - if not filename or (filename == "") then - filename = dataname .. input.lucsuffix - end - local blob = loadfile(file.join(pathname,filename)) - if not blob then - filename = dataname .. input.luasuffix - blob = loadfile(file.join(pathname,filename)) - end +function input.aux.load_texmfcnf(instance,dataname,pathname) + local filename = file.join(pathname,input.luaname) + local blob = loadfile(filename) if blob then - blob() - if (texmf.data.type == dataname) and (texmf.data.version == input.cacheversion) and texmf.data.content then - input.report("loading",dataname,"for",pathname,"from",filename) - instance[dataname][pathname] = texmf.data.content + local data = blob() + if data then + input.report("loading","configuration file",filename) + if true then + -- flatten to variable.progname + local t = { } + for k, v in pairs(data) do -- v = progname + if type(v) == "string" then + t[k] = v + else + for kk, vv in pairs(v) do -- vv = variable + if type(vv) == "string" then + t[vv.."."..v] = kk + end + end + end + end + instance[dataname][pathname] = t + else + instance[dataname][pathname] = data + end else - input.report("skipping",dataname,"for",pathname,"from",filename) + input.report("skipping","configuration file",filename) instance[dataname][pathname] = { } instance.loaderror = true end + else + input.report("skipping","configuration file",filename) + end +end + +function input.aux.load_configuration(instance,dname,lname) + input.aux.load_data(instance,dname,'configuration',lname and file.basename(lname)) +end +function input.aux.load_files(instance,tag) + input.aux.load_data(instance,tag,'files') +end + +function input.resetconfig(instance) + instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false +end + +function input.loadnewconfig(instance) + for _, cnf in ipairs(instance.luafiles) do + local dname = file.dirname(cnf) + input.aux.load_texmfcnf(instance,'setup',dname) + instance.order[#instance.order+1] = instance.setup[dname] + if instance.loaderror then break end + end +end + +function input.loadoldconfig(instance) + if not instance.renewcache then + for _, cnf in ipairs(instance.cnffiles) do + local dname = file.dirname(cnf) + input.aux.load_configuration(instance,dname) + instance.order[#instance.order+1] = instance.configuration[dname] + if instance.loaderror then break end + end end - texmf.data.content = { } + input.joinconfig(instance) end function input.expand_variables(instance) instance.expansions = { } - if instance.engine ~= "" then instance.environment['engine'] = instance.engine end - if instance.progname ~= "" then instance.environment['progname'] = instance.engine end +--~ instance.environment['SELFAUTOPARENT'] = instance.environment['SELFAUTOPARENT'] or instance.rootpath + if instance.engine ~= "" then instance.environment['engine'] = instance.engine end + if instance.progname ~= "" then instance.environment['progname'] = instance.progname end for k,v in pairs(instance.environment) do local a, b = k:match("^(%a+)%_(.*)%s*$") if a and b then @@ -3643,53 +3798,6 @@ function input.is_expansion(instance,name) return input.aux.is_entry(instance,instance.expansions,name) end -function input.aux.list(instance,list) - local pat = string.upper(instance.pattern or "","") - for _,key in pairs(table.sortedkeys(list)) do - if (instance.pattern=="") or string.find(key:upper(),pat) then - if instance.kpseonly then - if instance.kpsevars[key] then - print(key .. "=" .. input.aux.tabstr(list[key])) - end - elseif instance.kpsevars[key] then - print('K ' .. key .. "=" .. input.aux.tabstr(list[key])) - else - print('E ' .. key .. "=" .. input.aux.tabstr(list[key])) - end - end - end -end - -function input.list_variables(instance) - input.aux.list(instance,instance.variables) -end -function input.list_expansions(instance) - input.aux.list(instance,instance.expansions) -end - -function input.list_configurations(instance) - for _,key in pairs(table.sortedkeys(instance.kpsevars)) do - if not instance.pattern or (instance.pattern=="") or key:find(instance.pattern) then - print(key.."\n") - for i,c in ipairs(instance.order) do - local str = c[key] - if str then - print("\t" .. i .. "\t\t" .. input.aux.tabstr(str)) - end - end - print() - end - end -end - -function input.aux.tabstr(str) - if type(str) == 'table' then - return table.concat(str," | ") - else - return str - end -end - function input.simplified_list(str) if type(str) == 'table' then return str -- troubles ; ipv , in texmf @@ -3713,23 +3821,6 @@ function input.unexpanded_path(instance,str) return file.join_path(input.unexpanded_path_list(instance,str)) end ---~ function input.expanded_path_list(instance,str) ---~ if not str then ---~ return { } ---~ elseif instance.savelists then ---~ -- engine+progname hash ---~ str = str:gsub("%$","") ---~ if not instance.lists[str] then -- cached ---~ local lst = input.split_path(input.expansion(instance,str)) ---~ instance.lists[str] = input.aux.expanded_path(instance,lst) ---~ end ---~ return instance.lists[str] ---~ else ---~ local lst = input.split_path(input.expansion(instance,str)) ---~ return input.aux.expanded_path(instance,lst) ---~ end ---~ end - do local done = { } @@ -4142,6 +4233,8 @@ do return original end + input.normalize_name = file.collapse_path + end function input.aux.register_in_trees(instance,name) @@ -4507,7 +4600,10 @@ end function input.load(instance) input.starttiming(instance) + input.resetconfig(instance) input.identify_cnf(instance) + input.load_lua(instance) + input.expand_variables(instance) input.load_cnf(instance) input.expand_variables(instance) input.load_hash(instance) @@ -4894,28 +4990,45 @@ caches.more = caches.more or "context" caches.direct = false -- true is faster but may need huge amounts of memory caches.trace = false caches.tree = false -caches.temp = caches.temp or os.getenv("TEXMFCACHE") or os.getenv("HOME") or os.getenv("HOMEPATH") or os.getenv("VARTEXMF") or os.getenv("TEXMFVAR") or os.getenv("TMP") or os.getenv("TEMP") or os.getenv("TMPDIR") or nil -caches.paths = caches.paths or { caches.temp } +caches.paths = caches.paths or nil caches.force = false input.usecache = not toboolean(os.getenv("TEXMFSHARECACHE") or "false",true) -- true -if caches.temp and caches.temp ~= "" and lfs.attributes(caches.temp,"mode") ~= "directory" then - if caches.force or io.ask(string.format("Should I create the cache path %s?",caches.temp), "no", { "yes", "no" }) == "yes" then - dir.mkdirs(caches.temp) +function caches.temp(instance) + local function checkpath(cachepath) + if not cachepath or cachepath == "" then + return nil + elseif lfs.attributes(cachepath,"mode") == "directory" then -- lfs.isdir(cachepath) then + return cachepath + elseif caches.force or io.ask(string.format("Should I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then + dir.mkdirs(cachepath) + return (lfs.attributes(cachepath,"mode") == "directory") and cachepath + else + return nil + end end -end -if not caches.temp or caches.temp == "" then - print("\nfatal error: there is no valid cache path defined\n") - os.exit() -elseif lfs.attributes(caches.temp,"mode") ~= "directory" then - print(string.format("\nfatal error: cache path %s is not a directory\n",caches.temp)) - os.exit() + local cachepath = input.expanded_path_list(instance,"TEXMFCACHE") + cachepath = cachepath and #cachepath > 0 and checkpath(cachepath[1]) + if not cachepath then + cachepath = os.getenv("TEXMFCACHE") or os.getenv("HOME") or os.getenv("HOMEPATH") or os.getenv("TMP") or os.getenv("TEMP") or os.getenv("TMPDIR") or nil + cachepath = checkpath(cachepath) + end + if not cachepath then + print("\nfatal error: there is no valid cache path defined\n") + os.exit() + elseif lfs.attributes(cachepath,"mode") ~= "directory" then + print(string.format("\nfatal error: cache path %s is not a directory\n",cachepath)) + os.exit() + end + function caches.temp(instance) + return cachepath + end + return cachepath end function caches.configpath(instance) return table.concat(instance.cnffiles,";") ---~ return input.expand_var(instance,"TEXMFCNF") end function caches.hashed(tree) @@ -4933,19 +5046,8 @@ end function caches.setpath(instance,...) if not caches.path then - if lfs and instance then - for _,v in pairs(caches.paths) do - for _,vv in pairs(input.expanded_path_list(instance,v)) do - if lfs.isdir(vv) then - caches.path = vv - break - end - end - if caches.path then break end - end - end if not caches.path then - caches.path = caches.temp + caches.path = caches.temp(instance) end caches.path = input.clean_path(caches.path) -- to be sure if lfs then @@ -4969,6 +5071,12 @@ function caches.setpath(instance,...) return caches.path end +function caches.definepath(instance,category,subcategory) + return function() + return caches.setpath(instance,category,subcategory) + end +end + function caches.setluanames(path,name) return path .. "/" .. name .. ".tma", path .. "/" .. name .. ".tmc" end @@ -5034,19 +5142,35 @@ do -- local report end end + local allocated = { } + + -- tracing + function containers.define(category, subcategory, version, enabled) - if category and subcategory then - return { - category = category, - subcategory = subcategory, - storage = { }, - enabled = enabled, - version = version or 1.000, - trace = false, - path = caches.setpath(texmf.instance,category,subcategory), - } - else - return nil + return function() + if category and subcategory then + local c = allocated[category] + if not c then + c = { } + allocated[category] = c + end + local s = c[subcategory] + if not s then + s = { + category = category, + subcategory = subcategory, + storage = { }, + enabled = enabled, + version = version or 1.000, + trace = false, + path = caches.setpath(texmf.instance,category,subcategory), + } + c[subcategory] = s + end + return s + else + return nil + end end end @@ -5103,129 +5227,35 @@ end -- since we want to use the cache instead of the tree, we will now -- reimplement the saver. +local save_data = input.aux.save_data + +input.cachepath = nil + function input.aux.save_data(instance, dataname, check) - for cachename, files in pairs(instance[dataname]) do - local name + input.cachepath = input.cachepath or caches.definepath(instance,"trees") + save_data(instance, dataname, check, function(cachename,dataname) if input.usecache then - name = file.join(caches.setpath(instance,"trees"),caches.hashed(cachename)) - else - name = file.join(cachename,dataname) - end - local luaname, lucname = name .. input.luasuffix, name .. input.lucsuffix - input.report("preparing " .. dataname .. " in", luaname) - for k, v in pairs(files) do - if not check or check(v,k) then -- path, name - if type(v) == "table" and #v == 1 then - files[k] = v[1] - end - else - files[k] = nil -- false - end - end - local data = { - type = dataname, - root = cachename, - version = input.cacheversion, - date = os.date("%Y-%m-%d"), - time = os.date("%H:%M:%S"), - content = files, - } - local f = io.open(luaname,'w') - if f then - input.report("saving " .. dataname .. " in", luaname) - -- f:write(table.serialize(data,'return')) - f:write(input.serialize(data)) - f:close() - input.report("compiling " .. dataname .. " to", lucname) - if not utils.lua.compile(luaname,lucname) then - input.report("compiling failed for " .. dataname .. ", deleting file " .. lucname) - os.remove(lucname) - end + return file.join(input.cachepath(),caches.hashed(cachename)) else - input.report("unable to save " .. dataname .. " in " .. name..input.luasuffix) + return file.join(cachename,dataname) end - end + end) end -function input.serialize(files) - -- This version is somewhat optimized for the kind of - -- tables that we deal with, so it's much faster than - -- the generic serializer. This makes sense because - -- luatools and mtxtools are called frequently. Okay, - -- we pay a small price for properly tabbed tables. - local t = { } - local concat = table.concat - local sorted = table.sortedkeys - local function dump(k,v,m) - if type(v) == 'string' then - return m .. "['" .. k .. "']='" .. v .. "'," - elseif #v == 1 then - return m .. "['" .. k .. "']='" .. v[1] .. "'," - else - return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'}," - end - end - t[#t+1] = "return {" - if instance.sortdata then - for _, k in pairs(sorted(files)) do - local fk = files[k] - if type(fk) == 'table' then - t[#t+1] = "\t['" .. k .. "']={" - for _, kk in pairs(sorted(fk)) do - t[#t+1] = dump(kk,fk[kk],"\t\t") - end - t[#t+1] = "\t}," - else - t[#t+1] = dump(k,fk,"\t") - end - end - else - for k, v in pairs(files) do - if type(v) == 'table' then - t[#t+1] = "\t['" .. k .. "']={" - for kk,vv in pairs(v) do - t[#t+1] = dump(kk,vv,"\t\t") - end - t[#t+1] = "\t}," - else - t[#t+1] = dump(k,v,"\t") - end - end - end - t[#t+1] = "}" - return concat(t,"\n") -end +local load_data = input.aux.load_data function input.aux.load_data(instance,pathname,dataname,filename) - local luaname, lucname, pname, fname - if input.usecache then - pname, fname = caches.setpath(instance,"trees"), caches.hashed(pathname) - filename = file.join(pname,fname) - else - if not filename or (filename == "") then - filename = dataname - end - pname, fname = pathname, filename - end - luaname = file.join(pname,fname) .. input.luasuffix - lucname = file.join(pname,fname) .. input.lucsuffix - local blob = loadfile(lucname) - if not blob then - blob = loadfile(luaname) - end - if blob then - local data = blob() - if data and data.content and data.type == dataname and data.version == input.cacheversion then - input.report("loading",dataname,"for",pathname,"from",filename) - instance[dataname][pathname] = data.content + input.cachepath = input.cachepath or caches.definepath(instance,"trees") + load_data(instance,pathname,dataname,filename,function(dataname,filename) + if input.usecache then + return file.join(input.cachepath(),caches.hashed(pathname)) else - input.report("skipping",dataname,"for",pathname,"from",filename) - instance[dataname][pathname] = { } - instance.loaderror = true + if not filename or (filename == "") then + filename = dataname + end + return file.join(pathname,filename) end - else - input.report("skipping",dataname,"for",pathname,"from",filename) - end + end) end -- we will make a better format, maybe something xml or just text or lua @@ -5853,7 +5883,6 @@ if texconfig and not texlua then if not texmf.instance then -- prevent a second loading - texmf.instance = input.reset() texmf.instance.progname = environment.progname or 'context' texmf.instance.engine = environment.engine or 'luatex' @@ -6297,7 +6326,10 @@ if environment.arguments["minimize"] then end function input.my_prepare_a(instance) + input.resetconfig(instance) input.identify_cnf(instance) + input.load_lua(instance) + input.expand_variables(instance) input.load_cnf(instance) input.expand_variables(instance) end @@ -6472,6 +6504,51 @@ function input.my_run_format(instance,name,data,more) end end +-- helpers for verbose lists + +input.listers = input.listers or { } + +local function tabstr(str) + if type(str) == 'table' then + return table.concat(str," | ") + else + return str + end +end + +local function list(instance,list) + local pat = string.upper(instance.pattern or "","") + for _,key in pairs(table.sortedkeys(list)) do + if instance.pattern == "" or string.find(key:upper(),pat) then + if instance.kpseonly then + if instance.kpsevars[key] then + print(format("%s=%s",key,tabstr(list[key]))) + end + else + print(format('%s %s=%s',(instance.kpsevars[key] and 'K') or 'E',key,tabstr(list[key]))) + end + end + end +end + +function input.listers.variables (instance) list(instance,instance.variables ) end +function input.listers.expansions(instance) list(instance,instance.expansions) end + +function input.listers.configurations(instance) + for _,key in pairs(table.sortedkeys(instance.kpsevars)) do + if not instance.pattern or (instance.pattern=="") or key:find(instance.pattern) then + print(key.."\n") + for i,c in ipairs(instance.order) do + local str = c[key] + if str then + print(format("\t%s\t\t%s",i,input.aux.tabstr(str))) + end + end + print() + end + end +end + input.report(banner,"\n") local ok = true @@ -6545,13 +6622,13 @@ elseif environment.arguments["selfupdate"] then input.update_script(instance,own.name,"luatools") elseif environment.arguments["variables"] or environment.arguments["show-variables"] then input.my_prepare_a(instance) - input.list_variables(instance) + input.listers.variables(instance) elseif environment.arguments["expansions"] or environment.arguments["show-expansions"] then input.my_prepare_a(instance) - input.list_expansions(instance) + input.listers.expansions(instance) elseif environment.arguments["configurations"] or environment.arguments["show-configurations"] then input.my_prepare_a(instance) - input.list_configurations(instance) + input.listers.configurations(instance) elseif environment.arguments["help"] or (environment.files[1]=='help') or (#environment.files==0) then if not input.verbose then input.verbose = true diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua index ae0ee1b8e..6c444d531 100644 --- a/scripts/context/lua/mtx-context.lua +++ b/scripts/context/lua/mtx-context.lua @@ -583,7 +583,8 @@ function scripts.context.run(ctxdata) -- end else - input.error("no format found with name " .. formatname) + input.verbose = true + input.report("error", "no format found with name " .. formatname) end end end diff --git a/scripts/context/lua/mtx-server.lua b/scripts/context/lua/mtx-server.lua new file mode 100644 index 000000000..293bc0c1c --- /dev/null +++ b/scripts/context/lua/mtx-server.lua @@ -0,0 +1,83 @@ +if not modules then modules = { } end modules ['mtx-server'] = { + 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" +} + +texmf.instance = instance -- we need to get rid of this / maybe current instance in global table + +-- The starting point was stripped down webserver.lua by Samuel +-- Saint-Pettersen (as downloaded on 21-5-2008) which only served +-- html and was not configureable. In due time I will extend the +-- next code. Eventually we may move code to l-server. + +scripts = scripts or { } +scripts.webserver = scripts.webserver or {} + +local socket = require("socket") + +local function message(str) + return string.format("<h1>%s</h1>",str) +end + +function scripts.webserver.run(configuration) + local server = assert(socket.bind("*", tonumber(configuration.port or 8080))) + while true do + local client = server:accept() + client:settimeout(configuration.timeout or 60) + local request, e = client:receive() + if e then + client:send(message("404 Not Found")) + else + -- GET /showcase.pdf HTTP/1.1 + local filename = request:match("GET (.+) HTTP/.*$") -- todo: more clever + -- filename = filename:gsub("%%(%d%d)",function(c) return string.char(tonumber(c,16)) end) + filename = socket.url.unescape(filename) + if filename == nil or filename == "" then + filename = configuration.index or "index.html" + end + -- todo chunked + local fullname = file.join(configuration.root,filename) + local data = io.loaddata(fullname) + if data and data ~= "" then + local result + client:send("HTTP/1.1 200 OK\r\n") + client:send("Connection: close\r\n") + if filename:find(".pdf$") then -- todo: special handler + client:send(string.format("Content-Length: %s\r\n",#data)) + client:send("Content-Type: application/pdf\r\n") + else + client:send("Content-Type: text/html\r\n") + end + client:send("\r\n") + client:send(data) + client:send("\r\n") + else + client:send(message("404 Not Found")) + end + end + client:close() + end +end + + +banner = banner .. " | webserver " + +messages.help = [[ +--start start server +--port port to listen to +--root server root +--index index file +]] + +if environment.argument("start") then + scripts.webserver.run { + port = environment.argument("port") or "8080", + root = environment.argument("root") or ".", -- "e:/websites/www.pragma-ade.com", + index = environment.argument("index") or "index.html", + } +else + input.help(banner,messages.help) +end diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index 63605b42f..040214178 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -388,7 +388,6 @@ local patterns_escapes = { ["]"] = "%]", } - function string:pattesc() return (self:gsub(".",patterns_escapes)) end @@ -1701,14 +1700,22 @@ end --~ print("../test/" .. " == " .. file.collapse_path("../test/")) --~ print("a/a" .. " == " .. file.collapse_path("a/b/c/../../a")) +--~ function file.collapse_path(str) +--~ local ok, n = false, 0 +--~ while not ok do +--~ ok = true +--~ str, n = str:gsub("[^%./]+/%.%./", function(s) +--~ ok = false +--~ return "" +--~ end) +--~ end +--~ return (str:gsub("/%./","/")) +--~ end + function file.collapse_path(str) - local ok, n = false, 0 - while not ok do - ok = true - str, n = str:gsub("[^%./]+/%.%./", function(s) - ok = false - return "" - end) + local n = 1 + while n > 0 do + str, n = str:gsub("([^/%.]+/%.%./)","") end return (str:gsub("/%./","/")) end @@ -2307,7 +2314,7 @@ do local remove, nsremap, resolvens = table.remove, xml.xmlns, xml.resolvens - local stack, top, dt, at, xmlns, errorstr = {}, {}, {}, {}, {}, nil + local stack, top, dt, at, xmlns, errorstr, entities = {}, {}, {}, {}, {}, nil, {} local mt = { __tostring = xml.text } @@ -2383,14 +2390,6 @@ do dt[#dt+1] = text end end - --~ local function add_special(what, spacing, text) - --~ if #spacing > 0 then - --~ dt[#dt+1] = spacing - --~ end - --~ top = stack[#stack] -- hm, left over 1 - --~ setmetatable(top, mt) -- hm, left over 2 - --~ dt[#dt+1] = { special=true, ns="", tg=what, dt={text} } - --~ end local function add_special(what, spacing, text) if #spacing > 0 then dt[#dt+1] = spacing @@ -2450,12 +2449,20 @@ do local somecomment = C((1 - endcomment )^0) local somecdata = C((1 - endcdata )^0) + function entity(k,v) entities[k] = v end + local begindoctype = open * P("!DOCTYPE") local enddoctype = close - local publicdoctype = P("PUBLIC") * somespace * value * somespace * value * somespace * balanced^0 - local systemdoctype = P("SYSTEM") * somespace * value * somespace * balanced^0 - local simpledoctype = (1-close)^1 * balanced^0 - local somedoctype = C((somespace * P(publicdoctype + systemdoctype + simpledoctype) * optionalspace)^0) + local beginset = P("[") + local endset = P("]") + local doctypename = C((1-somespace)^0) + local elementdoctype = optionalspace * P("<!ELEMENT") * (1-close)^0 * close + local entitydoctype = optionalspace * P("<!ENTITY") * somespace * (doctypename * somespace * value)/entity * optionalspace * close + local publicdoctype = doctypename * somespace * P("PUBLIC") * somespace * value * somespace * value * somespace + local systemdoctype = doctypename * somespace * P("SYSTEM") * somespace * value * somespace + local definitiondoctype= doctypename * somespace * beginset * P(elementdoctype + entitydoctype)^0 * optionalspace * endset + local simpledoctype = (1-close)^1 -- * balanced^0 + local somedoctype = C((somespace * (publicdoctype + systemdoctype + definitiondoctype + simpledoctype) * optionalspace)^0) local instruction = (spacing * begininstruction * someinstruction * endinstruction) / function(...) add_special("@pi@",...) end local comment = (spacing * begincomment * somecomment * endcomment ) / function(...) add_special("@cm@",...) end @@ -2481,9 +2488,11 @@ do children = text + V("parent") + emptyelement + comment + cdata + instruction, } - function xml.convert(data, no_root, strip_cm_and_dt) + -- todo: xml.new + properties like entities and strip and such (store in root) + + function xml.convert(data, no_root, strip_cm_and_dt, given_entities) -- maybe use table met k/v (given_entities may disapear) strip = strip_cm_and_dt or xml.strip_cm_and_dt - stack, top, at, xmlns, errorstr, result = {}, {}, {}, {}, nil, nil + stack, top, at, xmlns, errorstr, result, entities = {}, {}, {}, {}, nil, nil, given_entities or {} stack[#stack+1] = top top.dt = { } dt = top.dt @@ -2502,7 +2511,7 @@ do result = stack[1] end if not no_root then - result = { special = true, ns = "", tg = '@rt@', dt = result.dt, at={} } + result = { special = true, ns = "", tg = '@rt@', dt = result.dt, at={}, entities = entities } setmetatable(result, mt) local rdt = result.dt for k=1,#rdt do @@ -2629,6 +2638,22 @@ do elseif not nocommands then local ec = e.command if ec ~= nil then -- we can have all kind of types + +if e.special then -- todo test for true/false + local etg, edt = e.tg, e.dt + local spc = specialconverter and specialconverter[etg] + if spc then +--~ print("SPECIAL",etg,table.serialize(specialconverter), spc) + local result = spc(edt[1]) + if result then + handle(result) + return + else + -- no need to handle any further + end + end +end + local xc = xml.command if xc then xc(e,ec) @@ -2678,12 +2703,18 @@ do end end end - if ern and xml.trace_remap then - if ats then - ats[#ats+1] = format("xmlns:remapped='%s'",ern) - else - ats = { format("xmlns:remapped='%s'",ern) } - end + if ern and xml.trace_remap and ern ~= ens then +--~ if ats then +--~ ats[#ats+1] = format("xmlns:remapped='%s'",ern) +--~ else +--~ ats = { format("xmlns:remapped='%s'",ern) } +--~ end +--~ if ats then +--~ ats[#ats+1] = format("remappedns='%s'",ens or '-') +--~ else +--~ ats = { format("remappedns='%s'",ens or '-') } +--~ end +ens = ern end if ens ~= "" then if edt and #edt > 0 then @@ -3261,10 +3292,10 @@ do end end functions.name = function(root,k,n) --- way too fuzzy + -- way too fuzzy local found if not k or not n then - local ns, tg = root.ns, root.tg + local ns, tg = root.rn or root.ns or "", root.tg if not tg then for i=1,#root do local e = root[i] @@ -3273,10 +3304,10 @@ do break end end - elseif ns == "" then - return tg - else + elseif ns ~= "" then return ns .. ":" .. tg + else + return tg end elseif n == 0 then local e = root[k] @@ -3296,6 +3327,7 @@ do end end else +--~ print(k,n,#root) for i=k+1,#root,1 do local e = root[i] if type(e) == "table" then @@ -3309,7 +3341,7 @@ do end end if found then - local ns, tg = found.ns, found.tg + local ns, tg = found.rn or found.ns or "", found.tg if ns ~= "" then return ns .. ":" .. tg else @@ -3709,7 +3741,7 @@ do end function xml.filters.tag(root,pattern,n) local tag = "" - xml.traverse(root, xml.lpath(pattern), function(r,d,k) + traverse(root, lpath(pattern), function(r,d,k) tag = xml.functions.tag(d,k,n and tonumber(n)) return true end) @@ -3717,7 +3749,7 @@ do end function xml.filters.name(root,pattern,n) local tag = "" - xml.traverse(root, xml.lpath(pattern), function(r,d,k) + traverse(root, lpath(pattern), function(r,d,k) tag = xml.functions.name(d,k,n and tonumber(n)) return true end) @@ -3748,8 +3780,13 @@ do local attribute_filter = xml.filters.attributes local default_filter = xml.filters.default + -- todo: also hash, could be gc'd + function xml.filter(root,pattern) local kind, a, b, c = parser:match(pattern) +--~ if xml.trace_lpath then +--~ print(pattern,kind,a,b,c) +--~ end if kind == 1 or kind == 3 then return (filters[b] or default_filter)(root,a,c) elseif kind == 2 then @@ -4292,7 +4329,7 @@ do if unicode and unicode.utf8 then xml.entities = xml.entities or { } -- xml.entities.handler == function function xml.entities.handler(e) - return format("[s]",e) + return format("[%s]",e) end local char = unicode.utf8.char @@ -4301,6 +4338,8 @@ do if unicode and unicode.utf8 then return char(tonumber(s,16)) end + local entities = xml.entities -- global entities + function utfize(root) local d = root.dt for k=1,#d do @@ -4318,8 +4357,6 @@ do if unicode and unicode.utf8 then xml.utfize = utfize - local entities = xml.entities - local function resolve(e) -- hex encoded always first, just to avoid mkii fallbacks if e:find("#x") then return char(tonumber(e:sub(3),16)) @@ -4334,20 +4371,24 @@ do if unicode and unicode.utf8 then end end - function xml.resolve_entities(root) - local d = root.dt - for k=1,#d do - local dk = d[k] - if type(dk) == "string" then - if dk:find("&.-;") then - d[k] = dk:gsub("&(.-);",resolve) + local function resolve_entities(root) + if not root.special or root.tg == "@rt@" then + local d = root.dt + for k=1,#d do + local dk = d[k] + if type(dk) == "string" then + if dk:find("&.-;") then + d[k] = dk:gsub("&(.-);",resolve) + end + else + resolve_entities(dk) end - else - utfize(dk) end end end + xml.resolve_entities = resolve_entities + function xml.utfize_text(str) if str:find("&#") then return (str:gsub("&#x(.-);",toutf)) @@ -4372,6 +4413,18 @@ do if unicode and unicode.utf8 then end end + -- experimental, this will be done differently + + function xml.merge_entities(root) + local documententities = root.entities + local allentities = xml.entities + if documententities then + for k, v in pairs(documententities) do + allentities[k] = v + end + end + end + end end -- xml.set_text_cleanup(xml.show_text_entities) @@ -4590,14 +4643,32 @@ os.platform = os.platform or os.type or (io.pathseparator == ";" and "windows") -- -- for k,v in pairs(arg) do print(k,v) end -if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then - arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil -end - -- environment if not environment then environment = { } end +environment.ownbin = environment.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex" + +local ownpath = nil -- we could use a metatable here + +function environment.ownpath() + if not ownpath then + for p in string.gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do + local b = file.join(p,environment.ownbin) + if lfs.isfile(b..".exe") or lfs.isfile(b) then + ownpath = p + break + end + end + if not ownpath then ownpath = '.' end + end + return ownpath +end + +if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then + arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil +end + environment.arguments = { } environment.files = { } environment.sorted_argument_keys = nil @@ -4709,6 +4780,10 @@ end -- additional functionality becomes available. We will split this -- module in components when we're done with prototyping. +-- TODO: os.getenv -> os.env[] +-- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller) +-- TODO: check escaping in find etc, too much, too slow + -- This is the first code I wrote for LuaTeX, so it needs some cleanup. -- To be considered: hash key lowercase, first entry in table filename @@ -4719,9 +4794,6 @@ end -- Beware, loading and saving is overloaded in luat-tmp! --- todo: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller) --- todo: check escaping in find etc, too much, too slow - if not versions then versions = { } end versions['luat-inp'] = 1.001 if not environment then environment = { } end if not file then file = { } end @@ -4740,6 +4812,8 @@ if not input.hashers then input.hashers = { } end -- load databases if not input.generators then input.generators = { } end -- generate databases if not input.filters then input.filters = { } end -- conversion filters +local format = string.format + input.locators.notfound = { nil } input.hashers.notfound = { nil } input.generators.notfound = { nil } @@ -4749,6 +4823,7 @@ input.banner = nil input.verbose = false input.debug = false input.cnfname = 'texmf.cnf' +input.luaname = 'texmfcnf.lua' input.lsrname = 'ls-R' input.luasuffix = '.tma' input.lucsuffix = '.tmc' @@ -4838,12 +4913,14 @@ function input.reset() instance.files = { } instance.remap = { } instance.configuration = { } + instance.setup = { } instance.order = { } instance.found = { } instance.foundintrees = { } instance.kpsevars = { } instance.hashes = { } instance.cnffiles = { } + instance.luafiles = { } instance.lists = { } instance.remember = true instance.diskcache = true @@ -4863,7 +4940,6 @@ function input.reset() instance.stoptime = 0 instance.validfile = function(path,name) return true end instance.data = { } -- only for loading - instance.sortdata = false instance.force_suffixes = true instance.dummy_path_expr = "^!*unset/*$" instance.fakepaths = { } @@ -4876,7 +4952,7 @@ function input.reset() end else -- we will access os.env frequently - for k,v in pairs({'HOME','TEXMF','TEXMFCNF','SELFAUTOPARENT'}) do + for k,v in pairs({'HOME','TEXMF','TEXMFCNF'}) do local e = os.getenv(v) if e then -- input.report("setting",v,"to",input.bare_variable(e)) @@ -4904,7 +4980,7 @@ function input.reset_hashes(instance) instance.found = { } end -function input.bare_variable(str) +function input.bare_variable(str) -- assumes str is a string -- return string.gsub(string.gsub(string.gsub(str,"%s+$",""),'^"(.+)"$',"%1"),"^'(.+)'$","%1") return (str:gsub("\s*([\"\']?)(.+)%1\s*", "%2")) end @@ -4989,7 +5065,7 @@ do instance.stoptime = stoptime instance.loadtime = instance.loadtime + loadtime if report then - input.report('load time', string.format("%0.3f",loadtime)) + input.report('load time', format("%0.3f",loadtime)) end return loadtime end @@ -5000,7 +5076,7 @@ do end function input.elapsedtime(instance) - return string.format("%0.3f",(instance and instance.loadtime) or 0) + return format("%0.3f",(instance and instance.loadtime) or 0) end function input.report_loadtime(instance) @@ -5016,15 +5092,19 @@ function input.env(instance,key) end function input.osenv(instance,key) - if instance.environment[key] == nil then - local e = os.getenv(key) + local ie = instance.environment + local value = ie[key] + if value == nil then + -- local e = os.getenv(key) + local e = os.env[key] if e == nil then - instance.environment[key] = "" -- false + -- value = "" -- false else - instance.environment[key] = input.bare_variable(e) + value = input.bare_variable(e) end + ie[key] = value end - return instance.environment[key] or "" + return value or "" end -- we follow a rather traditional approach: @@ -5035,66 +5115,103 @@ end -- for the moment we don't expect a configuration file in a zip function input.identify_cnf(instance) + -- we no longer support treepath and rootpath (was handy for testing); + -- also we now follow the stupid route: if not set then just assume *one* + -- cnf file under texmf (i.e. distribution) if #instance.cnffiles == 0 then - if instance.treepath ~= "" then - -- this is a special purpose branch, not really used - if instance.rootpath ~= "" then - local t = instance.treepath:splitchr(',') - for k,v in ipairs(t) do - t[k] = file.join(instance.rootpath,v) + if input.env(instance,'TEXMFCNF') == "" then + local ownpath = environment.ownpath() or "." + if ownpath then + -- beware, this is tricky on my own system because at that location I do have + -- the raw tree that ends up in the zip; i.e. I cannot test this kind of mess + local function locate(filename,list) + local ownroot = input.normalize_name(file.join(ownpath,"../..")) + if not lfs.isdir(file.join(ownroot,"texmf")) then + ownroot = input.normalize_name(file.join(ownpath,"..")) + if not lfs.isdir(file.join(ownroot,"texmf")) then + input.verbose = true + input.report("error", "unable to identify cnf file") + return + end + end + local texmfcnf = file.join(ownroot,"texmf-local/web2c",filename) -- for minimals and myself + if not lfs.isfile(texmfcnf) then + texmfcnf = file.join(ownroot,"texmf/web2c",filename) + if not lfs.isfile(texmfcnf) then + input.verbose = true + input.report("error", "unable to locate",filename) + return + end + end + table.insert(list,texmfcnf) + local ie = instance.environment + if not ie['SELFAUTOPARENT'] then ie['SELFAUTOPARENT'] = ownroot end + if not ie['TEXMFCNF'] then ie['TEXMFCNF'] = file.dirname(texmfcnf) end end - instance.treepath = table.concat(t,',') + locate(input.luaname,instance.luafiles) + locate(input.cnfname,instance.cnffiles) + if #instance.luafiles == 0 and instance.cnffiles == 0 then + input.verbose = true + input.report("error", "unable to locate",filename) + os.exit() + end + -- here we also assume then TEXMF is set in the distribution, if this trickery is + -- used in the minimals, then users who don't use setuptex are on their own with + -- regards to extra trees + else + input.verbose = true + input.report("error", "unable to identify own path") + os.exit() end - local t = instance.treepath:splitchr(',') - instance.environment['TEXMF'] = input.bare_variable(instance.treepath) - instance.environment['TEXMFCNF'] = file.join(t[1] or '.','texmf/web2c') - end - if instance.rootpath ~= "" then - -- this assumes a single path, maybe do an expanded split here too - instance.environment['TEXMFCNF'] = file.join(instance.rootpath,'texmf/web2c') - instance.environment['SELFAUTOPARENT'] = instance.rootpath - end - if input.env(instance,'TEXMFCNF') ~= "" then + else local t = input.split_path(input.env(instance,'TEXMFCNF')) t = input.aux.expanded_path(instance,t) input.aux.expand_vars(instance,t) - for _,v in ipairs(t) do - table.insert(instance.cnffiles,file.join(v,input.cnfname)) - end - elseif input.env(instance,'SELFAUTOPARENT') == '.' then - table.insert(instance.cnffiles,file.join('.',input.cnfname)) - else - for _,v in ipairs({'texmf-local','texmf'}) do - table.insert(instance.cnffiles,file.join(input.env(instance,'SELFAUTOPARENT'),v,'web2c',input.cnfname)) + local function locate(filename,list) + for _,v in ipairs(t) do + local texmfcnf = input.normalize_name(file.join(v,filename)) + if lfs.isfile(texmfcnf) then + table.insert(list,texmfcnf) + end + end end + locate(input.luaname,instance.luafiles) + locate(input.cnfname,instance.cnffiles) end end end function input.load_cnf(instance) + local function loadoldconfigdata() + for _, fname in ipairs(instance.cnffiles) do + input.aux.load_cnf(instance,fname) + end + end -- instance.cnffiles contain complete names now ! if #instance.cnffiles == 0 then input.report("no cnf files found (TEXMFCNF may not be set/known)") else instance.rootpath = instance.cnffiles[1] for k,fname in ipairs(instance.cnffiles) do - instance.cnffiles[k] = fname:gsub("\\",'/') -- needed? + instance.cnffiles[k] = input.normalize_name(fname:gsub("\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end + instance.rootpath = input.normalize_name(instance.rootpath) + instance.environment['SELFAUTOPARENT'] = instance.rootpath -- just to be sure if instance.lsrmode then - input.loadconfigdata(instance,instance.cnffiles) + loadoldconfigdata() elseif instance.diskcache and not instance.renewcache then - input.loadconfig(instance,instance.cnffiles) + input.loadoldconfig(instance,instance.cnffiles) if instance.loaderror then - input.loadconfigdata(instance,instance.cnffiles) - input.saveconfig(instance) + loadoldconfigdata() + input.saveoldconfig(instance) end else - input.loadconfigdata(instance,instance.cnffiles) + loadoldconfigdata() if instance.renewcache then - input.saveconfig(instance) + input.saveoldconfig(instance) end end input.aux.collapse_cnf_data(instance) @@ -5102,40 +5219,34 @@ function input.load_cnf(instance) input.checkconfigdata(instance) end -function input.loadconfigdata(instance) - for _, fname in ipairs(instance.cnffiles) do - input.aux.load_cnf(instance,fname) +function input.load_lua(instance) + if #instance.luafiles == 0 then + -- yet harmless + else + instance.rootpath = instance.luafiles[1] + for k,fname in ipairs(instance.luafiles) do + instance.luafiles[k] = input.normalize_name(fname:gsub("\\",'/')) + end + for i=1,3 do + instance.rootpath = file.dirname(instance.rootpath) + end + instance.rootpath = input.normalize_name(instance.rootpath) + instance.environment['SELFAUTOPARENT'] = instance.rootpath -- just to be sure + input.loadnewconfig(instance) + input.aux.collapse_cnf_data(instance) end + input.checkconfigdata(instance) end -if os.env then - function input.aux.collapse_cnf_data(instance) - for _,c in ipairs(instance.order) do - for k,v in pairs(c) do - if not instance.variables[k] then - if instance.environment[k] then - instance.variables[k] = instance.environment[k] - else - instance.kpsevars[k] = true - instance.variables[k] = input.bare_variable(v) - end - end - end - end - end -else - function input.aux.collapse_cnf_data(instance) - for _,c in ipairs(instance.order) do - for k,v in pairs(c) do - if not instance.variables[k] then - local e = os.getenv(k) - if e then - instance.environment[k] = input.bare_variable(e) - instance.variables[k] = instance.environment[k] - else - instance.variables[k] = input.bare_variable(v) - instance.kpsevars[k] = true - end +function input.aux.collapse_cnf_data(instance) -- potential optmization: pass start index (setup and configuration are shared) + for _,c in ipairs(instance.order) do + for k,v in pairs(c) do + if not instance.variables[k] then + if instance.environment[k] then + instance.variables[k] = instance.environment[k] + else + instance.kpsevars[k] = true + instance.variables[k] = input.bare_variable(v) end end end @@ -5146,11 +5257,11 @@ function input.aux.load_cnf(instance,fname) fname = input.clean_path(fname) local lname = fname:gsub("%.%a+$",input.luasuffix) local f = io.open(lname) - if f then + if f then -- this will go f:close() local dname = file.dirname(fname) if not instance.configuration[dname] then - input.aux.load_data(instance,dname,'configuration',file.basename(lname)) + input.aux.load_configuration(instance,dname,lname) instance.order[#instance.order+1] = instance.configuration[dname] end else @@ -5165,7 +5276,7 @@ function input.aux.load_cnf(instance,fname) end local data = instance.configuration[dname] while true do - line = f:read() + local line, n = f:read(), 0 if line then while true do -- join lines line, n = line:gsub("\\%s*$", "") @@ -5176,7 +5287,7 @@ function input.aux.load_cnf(instance,fname) end end if not line:find("^[%%#]") then - k, v = (line:gsub("%s*%%.*$","")):match("%s*(.-)%s*=%s*(.-)%s*$") + local k, v = (line:gsub("%s*%%.*$","")):match("%s*(.-)%s*=%s*(.-)%s*$") if k and v and not data[k] then data[k] = (v:gsub("[%%#].*",'')):gsub("~", "$HOME") instance.kpsevars[k] = true @@ -5250,6 +5361,7 @@ end function input.locatelists(instance) for _, path in pairs(input.simplified_list(input.expansion(instance,'TEXMF'))) do + path = file.collapse_path(path) input.report("locating list of",path) input.locatedatabase(instance,input.normalize_name(path)) end @@ -5286,7 +5398,7 @@ function input.loadfiles(instance) end function input.hashers.tex(instance,tag,name) - input.aux.load_data(instance,tag,'files') + input.aux.load_files(instance,tag) end -- generators: @@ -5363,7 +5475,7 @@ do end end action() - input.report(string.format("%s files found on %s directories with %s uppercase remappings",n,m,r)) + input.report(format("%s files found on %s directories with %s uppercase remappings",n,m,r)) else local fullname = file.join(specification,input.lsrname) local path = '.' @@ -5416,7 +5528,7 @@ end -- is more convenient. function input.splitconfig(instance) - for i,c in ipairs(instance.order) do + for i,c in ipairs(instance) do for k,v in pairs(c) do if type(v) == 'string' then local t = file.split_path(v) @@ -5450,14 +5562,7 @@ function input.join_path(str) return str end end ---~ function input.splitexpansions(instance) ---~ for k,v in pairs(instance.expansions) do ---~ local t = file.split_path(v) ---~ if #t > 1 then ---~ instance.expansions[k] = t ---~ end ---~ end ---~ end + function input.splitexpansions(instance) for k,v in pairs(instance.expansions) do local t, h = { }, { } @@ -5477,7 +5582,7 @@ end -- end of split/join code -function input.saveconfig(instance) +function input.saveoldconfig(instance) input.splitconfig(instance) input.aux.save_data(instance, 'configuration', nil) input.joinconfig(instance) @@ -5490,44 +5595,83 @@ input.configbanner = [[ -- not copyrighted. [HH & TH] ]] -function input.aux.save_data(instance, dataname, check) - for cachename, files in pairs(instance[dataname]) do - local name = file.join(cachename,dataname) - local luaname, lucname = name .. input.luasuffix, name .. input.lucsuffix - local f = io.open(luaname,'w') - if f then - input.report("saving " .. dataname .. " in", luaname) - f:write(input.configbanner) - f:write("\n") - f:write("if not texmf then texmf = { } end\n") - f:write("if not texmf.data then texmf.data = { } end\n") - f:write("\n") - f:write("texmf.data.type = '" .. dataname .. "'\n") - f:write("texmf.data.version = '" .. input.cacheversion .. "'\n") - f:write("texmf.data.date = '" .. os.date("%Y-%m-%d") .. "'\n") - f:write("texmf.data.time = '" .. os.date("%H:%M:%S") .. "'\n") - f:write('texmf.data.content = {\n') - local function dump(k,v) - if not check or check(v,k) then -- path, name - if type(v) == 'string' then - f:write("\t['" .. k .. "'] = '" .. v .. "',\n") - elseif #v == 1 then - f:write("\t['" .. k .. "'] = '" .. v[1] .. "',\n") - else - f:write("\t['" .. k .. "'] = {'" .. table.concat(v,"','").. "'},\n") - end +function input.serialize(files) + -- This version is somewhat optimized for the kind of + -- tables that we deal with, so it's much faster than + -- the generic serializer. This makes sense because + -- luatools and mtxtools are called frequently. Okay, + -- we pay a small price for properly tabbed tables. + local t = { } + local concat = table.concat + local sorted = table.sortedkeys + local function dump(k,v,m) + if type(v) == 'string' then + return m .. "['" .. k .. "']='" .. v .. "'," + elseif #v == 1 then + return m .. "['" .. k .. "']='" .. v[1] .. "'," + else + return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'}," + end + end + t[#t+1] = "return {" + if instance.sortdata then + for _, k in pairs(sorted(files)) do + local fk = files[k] + if type(fk) == 'table' then + t[#t+1] = "\t['" .. k .. "']={" + for _, kk in pairs(sorted(fk)) do + t[#t+1] = dump(kk,fk[kk],"\t\t") end + t[#t+1] = "\t}," + else + t[#t+1] = dump(k,fk,"\t") end - if instance.sortdata then - for _, k in pairs(table.sortedkeys(files)) do - dump(k,files[k]) + end + else + for k, v in pairs(files) do + if type(v) == 'table' then + t[#t+1] = "\t['" .. k .. "']={" + for kk,vv in pairs(v) do + t[#t+1] = dump(kk,vv,"\t\t") end + t[#t+1] = "\t}," else - for k, v in pairs(files) do - dump(k,v) + t[#t+1] = dump(k,v,"\t") + end + end + end + t[#t+1] = "}" + return concat(t,"\n") +end + +if not texmf then texmf = {} end -- no longer needed, at least not here + +function input.aux.save_data(instance, dataname, check, makename) -- untested without cache overload + for cachename, files in pairs(instance[dataname]) do + local name = (makename or file.join)(cachename,dataname) + local luaname, lucname = name .. input.luasuffix, name .. input.lucsuffix + input.report("preparing " .. dataname .. " for", luaname) + for k, v in pairs(files) do + if not check or check(v,k) then -- path, name + if type(v) == "table" and #v == 1 then + files[k] = v[1] end + else + files[k] = nil -- false end - f:write('}\n') + end + local data = { + type = dataname, + root = cachename, + version = input.cacheversion, + date = os.date("%Y-%m-%d"), + time = os.date("%H:%M:%S"), + content = files, + } + local f = io.open(luaname,'w') + if f then + input.report("saving " .. dataname .. " in", luaname) + f:write(input.serialize(data)) f:close() input.report("compiling " .. dataname .. " to", lucname) if not utils.lua.compile(luaname,lucname) then @@ -5540,49 +5684,106 @@ function input.aux.save_data(instance, dataname, check) end end -function input.loadconfig(instance) - instance.configuration, instance.order, instance.loaderror = { }, { }, false - if not instance.renewcache then - for _, cnf in ipairs(instance.cnffiles) do - local dname = file.dirname(cnf) - input.aux.load_data(instance,dname,'configuration') - instance.order[#instance.order+1] = instance.configuration[dname] - if instance.loaderror then break end +function input.aux.load_data(instance,pathname,dataname,filename,makename) -- untested without cache overload + filename = ((not filename or (filename == "")) and dataname) or filename + filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) + local blob = loadfile(filename .. input.lucsuffix) or loadfile(filename .. input.luasuffix) + if blob then + local data = blob() + if data and data.content and data.type == dataname and data.version == input.cacheversion then + input.report("loading",dataname,"for",pathname,"from",filename) + instance[dataname][pathname] = data.content + else + input.report("skipping",dataname,"for",pathname,"from",filename) + instance[dataname][pathname] = { } + instance.loaderror = true end + else + input.report("skipping",dataname,"for",pathname,"from",filename) end - input.joinconfig(instance) end -if not texmf then texmf = {} end -if not texmf.data then texmf.data = {} end +-- some day i'll use the nested approach, but not yet (actually we even drop +-- engine/progname support since we have only luatex now) +-- +-- first texmfcnf.lua files are located, next the cached texmf.cnf files +-- +-- return { +-- TEXMFBOGUS = 'effe checken of dit werkt', +-- } -function input.aux.load_data(instance,pathname,dataname,filename) - if not filename or (filename == "") then - filename = dataname .. input.lucsuffix - end - local blob = loadfile(file.join(pathname,filename)) - if not blob then - filename = dataname .. input.luasuffix - blob = loadfile(file.join(pathname,filename)) - end +function input.aux.load_texmfcnf(instance,dataname,pathname) + local filename = file.join(pathname,input.luaname) + local blob = loadfile(filename) if blob then - blob() - if (texmf.data.type == dataname) and (texmf.data.version == input.cacheversion) and texmf.data.content then - input.report("loading",dataname,"for",pathname,"from",filename) - instance[dataname][pathname] = texmf.data.content + local data = blob() + if data then + input.report("loading","configuration file",filename) + if true then + -- flatten to variable.progname + local t = { } + for k, v in pairs(data) do -- v = progname + if type(v) == "string" then + t[k] = v + else + for kk, vv in pairs(v) do -- vv = variable + if type(vv) == "string" then + t[vv.."."..v] = kk + end + end + end + end + instance[dataname][pathname] = t + else + instance[dataname][pathname] = data + end else - input.report("skipping",dataname,"for",pathname,"from",filename) + input.report("skipping","configuration file",filename) instance[dataname][pathname] = { } instance.loaderror = true end + else + input.report("skipping","configuration file",filename) + end +end + +function input.aux.load_configuration(instance,dname,lname) + input.aux.load_data(instance,dname,'configuration',lname and file.basename(lname)) +end +function input.aux.load_files(instance,tag) + input.aux.load_data(instance,tag,'files') +end + +function input.resetconfig(instance) + instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false +end + +function input.loadnewconfig(instance) + for _, cnf in ipairs(instance.luafiles) do + local dname = file.dirname(cnf) + input.aux.load_texmfcnf(instance,'setup',dname) + instance.order[#instance.order+1] = instance.setup[dname] + if instance.loaderror then break end + end +end + +function input.loadoldconfig(instance) + if not instance.renewcache then + for _, cnf in ipairs(instance.cnffiles) do + local dname = file.dirname(cnf) + input.aux.load_configuration(instance,dname) + instance.order[#instance.order+1] = instance.configuration[dname] + if instance.loaderror then break end + end end - texmf.data.content = { } + input.joinconfig(instance) end function input.expand_variables(instance) instance.expansions = { } - if instance.engine ~= "" then instance.environment['engine'] = instance.engine end - if instance.progname ~= "" then instance.environment['progname'] = instance.engine end +--~ instance.environment['SELFAUTOPARENT'] = instance.environment['SELFAUTOPARENT'] or instance.rootpath + if instance.engine ~= "" then instance.environment['engine'] = instance.engine end + if instance.progname ~= "" then instance.environment['progname'] = instance.progname end for k,v in pairs(instance.environment) do local a, b = k:match("^(%a+)%_(.*)%s*$") if a and b then @@ -5673,53 +5874,6 @@ function input.is_expansion(instance,name) return input.aux.is_entry(instance,instance.expansions,name) end -function input.aux.list(instance,list) - local pat = string.upper(instance.pattern or "","") - for _,key in pairs(table.sortedkeys(list)) do - if (instance.pattern=="") or string.find(key:upper(),pat) then - if instance.kpseonly then - if instance.kpsevars[key] then - print(key .. "=" .. input.aux.tabstr(list[key])) - end - elseif instance.kpsevars[key] then - print('K ' .. key .. "=" .. input.aux.tabstr(list[key])) - else - print('E ' .. key .. "=" .. input.aux.tabstr(list[key])) - end - end - end -end - -function input.list_variables(instance) - input.aux.list(instance,instance.variables) -end -function input.list_expansions(instance) - input.aux.list(instance,instance.expansions) -end - -function input.list_configurations(instance) - for _,key in pairs(table.sortedkeys(instance.kpsevars)) do - if not instance.pattern or (instance.pattern=="") or key:find(instance.pattern) then - print(key.."\n") - for i,c in ipairs(instance.order) do - local str = c[key] - if str then - print("\t" .. i .. "\t\t" .. input.aux.tabstr(str)) - end - end - print() - end - end -end - -function input.aux.tabstr(str) - if type(str) == 'table' then - return table.concat(str," | ") - else - return str - end -end - function input.simplified_list(str) if type(str) == 'table' then return str -- troubles ; ipv , in texmf @@ -5743,23 +5897,6 @@ function input.unexpanded_path(instance,str) return file.join_path(input.unexpanded_path_list(instance,str)) end ---~ function input.expanded_path_list(instance,str) ---~ if not str then ---~ return { } ---~ elseif instance.savelists then ---~ -- engine+progname hash ---~ str = str:gsub("%$","") ---~ if not instance.lists[str] then -- cached ---~ local lst = input.split_path(input.expansion(instance,str)) ---~ instance.lists[str] = input.aux.expanded_path(instance,lst) ---~ end ---~ return instance.lists[str] ---~ else ---~ local lst = input.split_path(input.expansion(instance,str)) ---~ return input.aux.expanded_path(instance,lst) ---~ end ---~ end - do local done = { } @@ -6172,6 +6309,8 @@ do return original end + input.normalize_name = file.collapse_path + end function input.aux.register_in_trees(instance,name) @@ -6537,7 +6676,10 @@ end function input.load(instance) input.starttiming(instance) + input.resetconfig(instance) input.identify_cnf(instance) + input.load_lua(instance) + input.expand_variables(instance) input.load_cnf(instance) input.expand_variables(instance) input.load_hash(instance) @@ -6924,28 +7066,45 @@ caches.more = caches.more or "context" caches.direct = false -- true is faster but may need huge amounts of memory caches.trace = false caches.tree = false -caches.temp = caches.temp or os.getenv("TEXMFCACHE") or os.getenv("HOME") or os.getenv("HOMEPATH") or os.getenv("VARTEXMF") or os.getenv("TEXMFVAR") or os.getenv("TMP") or os.getenv("TEMP") or os.getenv("TMPDIR") or nil -caches.paths = caches.paths or { caches.temp } +caches.paths = caches.paths or nil caches.force = false input.usecache = not toboolean(os.getenv("TEXMFSHARECACHE") or "false",true) -- true -if caches.temp and caches.temp ~= "" and lfs.attributes(caches.temp,"mode") ~= "directory" then - if caches.force or io.ask(string.format("Should I create the cache path %s?",caches.temp), "no", { "yes", "no" }) == "yes" then - dir.mkdirs(caches.temp) +function caches.temp(instance) + local function checkpath(cachepath) + if not cachepath or cachepath == "" then + return nil + elseif lfs.attributes(cachepath,"mode") == "directory" then -- lfs.isdir(cachepath) then + return cachepath + elseif caches.force or io.ask(string.format("Should I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then + dir.mkdirs(cachepath) + return (lfs.attributes(cachepath,"mode") == "directory") and cachepath + else + return nil + end end -end -if not caches.temp or caches.temp == "" then - print("\nfatal error: there is no valid cache path defined\n") - os.exit() -elseif lfs.attributes(caches.temp,"mode") ~= "directory" then - print(string.format("\nfatal error: cache path %s is not a directory\n",caches.temp)) - os.exit() + local cachepath = input.expanded_path_list(instance,"TEXMFCACHE") + cachepath = cachepath and #cachepath > 0 and checkpath(cachepath[1]) + if not cachepath then + cachepath = os.getenv("TEXMFCACHE") or os.getenv("HOME") or os.getenv("HOMEPATH") or os.getenv("TMP") or os.getenv("TEMP") or os.getenv("TMPDIR") or nil + cachepath = checkpath(cachepath) + end + if not cachepath then + print("\nfatal error: there is no valid cache path defined\n") + os.exit() + elseif lfs.attributes(cachepath,"mode") ~= "directory" then + print(string.format("\nfatal error: cache path %s is not a directory\n",cachepath)) + os.exit() + end + function caches.temp(instance) + return cachepath + end + return cachepath end function caches.configpath(instance) return table.concat(instance.cnffiles,";") ---~ return input.expand_var(instance,"TEXMFCNF") end function caches.hashed(tree) @@ -6963,19 +7122,8 @@ end function caches.setpath(instance,...) if not caches.path then - if lfs and instance then - for _,v in pairs(caches.paths) do - for _,vv in pairs(input.expanded_path_list(instance,v)) do - if lfs.isdir(vv) then - caches.path = vv - break - end - end - if caches.path then break end - end - end if not caches.path then - caches.path = caches.temp + caches.path = caches.temp(instance) end caches.path = input.clean_path(caches.path) -- to be sure if lfs then @@ -6999,6 +7147,12 @@ function caches.setpath(instance,...) return caches.path end +function caches.definepath(instance,category,subcategory) + return function() + return caches.setpath(instance,category,subcategory) + end +end + function caches.setluanames(path,name) return path .. "/" .. name .. ".tma", path .. "/" .. name .. ".tmc" end @@ -7064,19 +7218,35 @@ do -- local report end end + local allocated = { } + + -- tracing + function containers.define(category, subcategory, version, enabled) - if category and subcategory then - return { - category = category, - subcategory = subcategory, - storage = { }, - enabled = enabled, - version = version or 1.000, - trace = false, - path = caches.setpath(texmf.instance,category,subcategory), - } - else - return nil + return function() + if category and subcategory then + local c = allocated[category] + if not c then + c = { } + allocated[category] = c + end + local s = c[subcategory] + if not s then + s = { + category = category, + subcategory = subcategory, + storage = { }, + enabled = enabled, + version = version or 1.000, + trace = false, + path = caches.setpath(texmf.instance,category,subcategory), + } + c[subcategory] = s + end + return s + else + return nil + end end end @@ -7133,129 +7303,35 @@ end -- since we want to use the cache instead of the tree, we will now -- reimplement the saver. +local save_data = input.aux.save_data + +input.cachepath = nil + function input.aux.save_data(instance, dataname, check) - for cachename, files in pairs(instance[dataname]) do - local name + input.cachepath = input.cachepath or caches.definepath(instance,"trees") + save_data(instance, dataname, check, function(cachename,dataname) if input.usecache then - name = file.join(caches.setpath(instance,"trees"),caches.hashed(cachename)) - else - name = file.join(cachename,dataname) - end - local luaname, lucname = name .. input.luasuffix, name .. input.lucsuffix - input.report("preparing " .. dataname .. " in", luaname) - for k, v in pairs(files) do - if not check or check(v,k) then -- path, name - if type(v) == "table" and #v == 1 then - files[k] = v[1] - end - else - files[k] = nil -- false - end - end - local data = { - type = dataname, - root = cachename, - version = input.cacheversion, - date = os.date("%Y-%m-%d"), - time = os.date("%H:%M:%S"), - content = files, - } - local f = io.open(luaname,'w') - if f then - input.report("saving " .. dataname .. " in", luaname) - -- f:write(table.serialize(data,'return')) - f:write(input.serialize(data)) - f:close() - input.report("compiling " .. dataname .. " to", lucname) - if not utils.lua.compile(luaname,lucname) then - input.report("compiling failed for " .. dataname .. ", deleting file " .. lucname) - os.remove(lucname) - end + return file.join(input.cachepath(),caches.hashed(cachename)) else - input.report("unable to save " .. dataname .. " in " .. name..input.luasuffix) + return file.join(cachename,dataname) end - end + end) end -function input.serialize(files) - -- This version is somewhat optimized for the kind of - -- tables that we deal with, so it's much faster than - -- the generic serializer. This makes sense because - -- luatools and mtxtools are called frequently. Okay, - -- we pay a small price for properly tabbed tables. - local t = { } - local concat = table.concat - local sorted = table.sortedkeys - local function dump(k,v,m) - if type(v) == 'string' then - return m .. "['" .. k .. "']='" .. v .. "'," - elseif #v == 1 then - return m .. "['" .. k .. "']='" .. v[1] .. "'," - else - return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'}," - end - end - t[#t+1] = "return {" - if instance.sortdata then - for _, k in pairs(sorted(files)) do - local fk = files[k] - if type(fk) == 'table' then - t[#t+1] = "\t['" .. k .. "']={" - for _, kk in pairs(sorted(fk)) do - t[#t+1] = dump(kk,fk[kk],"\t\t") - end - t[#t+1] = "\t}," - else - t[#t+1] = dump(k,fk,"\t") - end - end - else - for k, v in pairs(files) do - if type(v) == 'table' then - t[#t+1] = "\t['" .. k .. "']={" - for kk,vv in pairs(v) do - t[#t+1] = dump(kk,vv,"\t\t") - end - t[#t+1] = "\t}," - else - t[#t+1] = dump(k,v,"\t") - end - end - end - t[#t+1] = "}" - return concat(t,"\n") -end +local load_data = input.aux.load_data function input.aux.load_data(instance,pathname,dataname,filename) - local luaname, lucname, pname, fname - if input.usecache then - pname, fname = caches.setpath(instance,"trees"), caches.hashed(pathname) - filename = file.join(pname,fname) - else - if not filename or (filename == "") then - filename = dataname - end - pname, fname = pathname, filename - end - luaname = file.join(pname,fname) .. input.luasuffix - lucname = file.join(pname,fname) .. input.lucsuffix - local blob = loadfile(lucname) - if not blob then - blob = loadfile(luaname) - end - if blob then - local data = blob() - if data and data.content and data.type == dataname and data.version == input.cacheversion then - input.report("loading",dataname,"for",pathname,"from",filename) - instance[dataname][pathname] = data.content + input.cachepath = input.cachepath or caches.definepath(instance,"trees") + load_data(instance,pathname,dataname,filename,function(dataname,filename) + if input.usecache then + return file.join(input.cachepath(),caches.hashed(pathname)) else - input.report("skipping",dataname,"for",pathname,"from",filename) - instance[dataname][pathname] = { } - instance.loaderror = true + if not filename or (filename == "") then + filename = dataname + end + return file.join(pathname,filename) end - else - input.report("skipping",dataname,"for",pathname,"from",filename) - end + end) end -- we will make a better format, maybe something xml or just text or lua @@ -8027,7 +8103,10 @@ messages.help = [[ ]] function input.runners.my_prepare_a(instance) + input.resetconfig(instance) input.identify_cnf(instance) + input.load_lua(instance) + input.expand_variables(instance) input.load_cnf(instance) input.expand_variables(instance) end @@ -8035,6 +8114,7 @@ end function input.runners.my_prepare_b(instance) input.runners.my_prepare_a(instance) input.load_hash(instance) + input.automount(instance) end function input.runners.prepare(instance) diff --git a/tex/context/base/cont-new.tex b/tex/context/base/cont-new.tex index bf5540405..eda6471d2 100644 --- a/tex/context/base/cont-new.tex +++ b/tex/context/base/cont-new.tex @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2008.05.13 14:42} +\newcontextversion{2008.05.21 15:21} %D This file is loaded at runtime, thereby providing an %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/context.tex b/tex/context/base/context.tex index c0f4c7afe..e6959c9b4 100644 --- a/tex/context/base/context.tex +++ b/tex/context/base/context.tex @@ -42,7 +42,7 @@ %D your styles an modules. \edef\contextformat {\jobname} -\edef\contextversion{2008.05.13 14:42} +\edef\contextversion{2008.05.21 15:21} %D For those who want to use this: diff --git a/tex/context/base/core-buf.lua b/tex/context/base/core-buf.lua index 4203486f6..7c0164cf5 100644 --- a/tex/context/base/core-buf.lua +++ b/tex/context/base/core-buf.lua @@ -217,15 +217,24 @@ function buffers.content(name) -- no print end end -function buffers.collect(names) -- no print +function buffers.collect(names,separator) -- no print local t = { } - for i=1,#names do - local c = buffers.content(names[i]) - if c ~= "" then - t[#t+1] = c + if type(names) == "table" then + for i=1,#names do + local c = buffers.content(names[i]) + if c ~= "" then + t[#t+1] = c + end + end + else + for name in names:gmatch("[^,]+") do + local c = buffers.content(name) + if c ~= "" then + t[#t+1] = c + end end end - return concat(t," ") + return concat(t,separator or " ") -- maybe this will change to "\n" end function buffers.inspect(name) diff --git a/tex/context/base/core-lst.tex b/tex/context/base/core-lst.tex index 5f08146dc..d9fdca375 100644 --- a/tex/context/base/core-lst.tex +++ b/tex/context/base/core-lst.tex @@ -66,7 +66,7 @@ \thisisnextinternal\currentlist \fi \expanded - {\writeutilitycommand + {\writeutilitycommand % todo: also an immediate option {\noexpand\listentry {\currentlist}% {\nextinternalreference}% diff --git a/tex/context/base/core-mat.tex b/tex/context/base/core-mat.tex index 465e8d50b..a74d5f90e 100644 --- a/tex/context/base/core-mat.tex +++ b/tex/context/base/core-mat.tex @@ -17,6 +17,18 @@ \unprotect +% \startlines +% $\mathopnolimits{\rm d}x$ +% $\mathopnolimits{\kern\zeropoint \rm d}x$ +% $\puremathcomm{nolop}{\rm d}x$ +% $\puremathcomm{nolop}{\kern\zeropoint\rm d}x$ +% \blank +% $\puremathcomm{nolop}{\mr d}x$ +% $\puremathcomm{nolop}{\kern\zeropoint\mr d}x$ +% $\mathop{\kern\zeropoint\mr d}x$ +% $\mathopnolimits{\kern\zeropoint d}x$ +% \stoplines + % \definemessageconstant{math} % \startmessages all library: math @@ -2759,6 +2771,7 @@ \def\disablefiller {\let\normalorfiller\firstoftwoarguments} \def\mathopnolimits#1{\mathop{\mr#1}\nolimits} % was \rm, which follows text fonts (used in mml parser) +\def\mathopdolimits#1{\mathop{\mr#1}} % was \rm, which follows text fonts (used in mml parser) %D \macros{overset, underset} %D diff --git a/tex/context/base/core-ver.mkiv b/tex/context/base/core-ver.mkiv index c1dc0c72a..701d19b41 100644 --- a/tex/context/base/core-ver.mkiv +++ b/tex/context/base/core-ver.mkiv @@ -36,6 +36,7 @@ {\ctxlua{buffers.visualizers.reset()}% \def\obs{\obeyedspace}% \verbatimfont + \resetfontfeature \obeycharacters} % \ctxluafileload{verb-tex}{} diff --git a/tex/context/base/font-afm.lua b/tex/context/base/font-afm.lua index 0bed489d8..fd9315472 100644 --- a/tex/context/base/font-afm.lua +++ b/tex/context/base/font-afm.lua @@ -19,7 +19,7 @@ away.</p> fonts = fonts or { } fonts.afm = fonts.afm or { } -fonts.afm.version = 1.25 -- incrementing this number one up will force a re-cache +fonts.afm.version = 1.26 -- incrementing this number one up will force a re-cache fonts.afm.syncspace = true -- when true, nicer stretch values fonts.afm.enhance_data = true -- best leave this set to true fonts.afm.trace_features = false @@ -254,7 +254,7 @@ way we can set them faster when defining a font.</p> function fonts.afm.load(filename) local name = file.removesuffix(filename) - local data = containers.read(fonts.afm.cache,name) + local data = containers.read(fonts.afm.cache(),name) local size = lfs.attributes(name,"size") or 0 if data and data.size ~= size then data = nil @@ -273,7 +273,7 @@ function fonts.afm.load(filename) logs.report("load afm","file size: " .. size) data.size = size logs.report("load afm","saving: in cache") - data = containers.write(fonts.afm.cache, name, data) + data = containers.write(fonts.afm.cache(), name, data) end end end @@ -281,7 +281,8 @@ function fonts.afm.load(filename) end function fonts.afm.unify(data, filename) - local unicode, private, unicodes = fonts.enc.load('unicode').hash, 0x0F0000, { } +--~ local unicode, unicodes, private = fonts.enc.load('unicode').hash, { }, 0x0F0000 + local unicode, unicodes, private = fonts.enc.load('unicode').hash, { }, fonts.private for name, blob in pairs(data.characters) do local code = unicode[name] -- or characters.name_to_unicode[name] if not code then @@ -571,9 +572,10 @@ function fonts.afm.afm_to_tfm(specification) return nil else fonts.afm.check_features(specification) + specification = fonts.define.resolve(specification) -- new, was forgotten local features = specification.features.normal local cache_id = specification.hash - local tfmdata = containers.read(fonts.tfm.cache, cache_id) -- cache with features applied + local tfmdata = containers.read(fonts.tfm.cache(), cache_id) -- cache with features applied if not tfmdata then local afmdata = fonts.afm.load(afmname) if not table.is_empty(afmdata) then @@ -589,7 +591,7 @@ function fonts.afm.afm_to_tfm(specification) elseif fonts.trace then logs.report("load afm", string.format("no (valid) afm file found with name %s",afmname)) end - tfmdata = containers.write(fonts.tfm.cache,cache_id,tfmdata) + tfmdata = containers.write(fonts.tfm.cache(),cache_id,tfmdata) end return tfmdata end @@ -731,4 +733,13 @@ fonts.afm.features.register('encoding') fonts.initializers.base.afm.encoding = fonts.initializers.common.encoding fonts.initializers.node.afm.encoding = fonts.initializers.common.encoding --- todo: oldstyle smallcaps as features for afm files +-- todo: oldstyle smallcaps as features for afm files (use with care) + +fonts.initializers.base.afm.onum = fonts.initializers.common.oldstyle +fonts.initializers.base.afm.smcp = fonts.initializers.common.smallcaps +fonts.initializers.base.afm.fkcp = fonts.initializers.common.fakecaps + +fonts.afm.features.register('onum',false) +fonts.afm.features.register('smcp',false) +fonts.afm.features.register('fkcp',false) + diff --git a/tex/context/base/font-def.lua b/tex/context/base/font-def.lua index c9a3144f5..af6f5f394 100644 --- a/tex/context/base/font-def.lua +++ b/tex/context/base/font-def.lua @@ -277,7 +277,7 @@ function fonts.tfm.read_and_define(name,size) -- no id fonts.tfm.id[id] = fontdata fonts.tfm.internalized[hash] = id if fonts.trace then - logs.report("define font", string.format("at 1 id %s, hash: %s",id,hash)) + logs.report("define font", string.format("loading at 1 id %s, hash: %s",id,hash)) end else id = fonts.tfm.internalized[hash] @@ -602,7 +602,7 @@ function fonts.define.read(name,size,id) specification = fonts.define.resolve(specification) local hash = fonts.tfm.hash_instance(specification) if true then - --~ local fontdata = containers.read(fonts.cache,hash) -- for tracing purposes + --~ local fontdata = containers.read(fonts.cache(),hash) -- for tracing purposes end local fontdata = fonts.tfm.internalized[hash] -- id if not fontdata then @@ -615,23 +615,24 @@ function fonts.define.read(name,size,id) end end if true then - --~ fontdata = containers.write(fonts.cache,hash,fontdata) -- for tracing purposes + --~ fontdata = containers.write(fonts.cache(),hash,fontdata) -- for tracing purposes end if not fonts.tfm.internalized[hash] then fonts.tfm.id[id] = fontdata fonts.tfm.internalized[hash] = id if fonts.trace then - logs.report("define font", string.format("at 2 id %s, hash: %s",id,hash)) + logs.report("define font", string.format("loading at 2 id %s, hash: %s",id,hash)) end else fontdata = fonts.tfm.internalized[hash] end end if not fontdata then - logs.error("define font", string.format("name: %s, loading aborted",specification.name)) + logs.error("define font", string.format("unknown font %s, loading aborted",specification.name)) elseif fonts.trace and type(fontdata) == "table" then - logs.report("use font",string.format("%s font n:%s s:%s b:%s e:%s p:%s f:%s", + logs.report("define font",string.format("using %s font with id %s, n:%s s:%s b:%s e:%s p:%s f:%s", fontdata.type or "unknown", + id or "?", fontdata.name or "?", fontdata.size or "default", fontdata.encodingbytes or "?", diff --git a/tex/context/base/font-enc.lua b/tex/context/base/font-enc.lua index 73b4ae5d8..fc77aefb9 100644 --- a/tex/context/base/font-enc.lua +++ b/tex/context/base/font-enc.lua @@ -27,7 +27,7 @@ fonts.enc.known = { } function fonts.enc.is_known(encoding) - return containers.is_valid(fonts.enc.cache,encoding) + return containers.is_valid(fonts.enc.cache(),encoding) end --[[ldx-- @@ -51,7 +51,7 @@ will be used.</p> function fonts.enc.load(filename) local name = file.removesuffix(filename) - local data = containers.read(fonts.enc.cache,name) + local data = containers.read(fonts.enc.cache(),name) if data then return data end @@ -93,7 +93,7 @@ function fonts.enc.load(filename) hash=hash, unicodes=unicodes } - return containers.write(fonts.enc.cache, name, data) + return containers.write(fonts.enc.cache(), name, data) end --[[ldx-- @@ -116,5 +116,5 @@ function fonts.enc.make_unicode_vector() for name, code in pairs(characters.synonyms) do vector[code], hash[name] = name, code end - return containers.write(fonts.enc.cache, 'unicode', { name='unicode', tag='unicode', vector=vector, hash=hash }) + return containers.write(fonts.enc.cache(), 'unicode', { name='unicode', tag='unicode', vector=vector, hash=hash }) end diff --git a/tex/context/base/font-ini.lua b/tex/context/base/font-ini.lua index 0cfc7a3f4..a3eefa9db 100644 --- a/tex/context/base/font-ini.lua +++ b/tex/context/base/font-ini.lua @@ -15,8 +15,9 @@ if not modules then modules = { } end modules ['font-ini'] = { fonts = fonts or { } -fonts.trace = false -- true -fonts.mode = 'base' +fonts.trace = false -- true +fonts.mode = 'base' +fonts.private = 0xE000 fonts.methods = { base = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } }, diff --git a/tex/context/base/font-otf.lua b/tex/context/base/font-otf.lua index 9efa88e50..5c0db392d 100644 --- a/tex/context/base/font-otf.lua +++ b/tex/context/base/font-otf.lua @@ -830,7 +830,7 @@ function fonts.otf.load(filename,format,sub,featurefile) hash = hash:lower() hash = hash:gsub("[^%w%d]+","-") end - local data = containers.read(fonts.otf.cache, hash) + local data = containers.read(fonts.otf.cache(), hash) local size = lfs.attributes(filename,"size") or 0 if data and data.size ~= size then data = nil @@ -886,7 +886,7 @@ function fonts.otf.load(filename,format,sub,featurefile) logs.report("load otf","file size: " .. size) data.size = size logs.report("load otf","saving: in cache") - data = containers.write(fonts.otf.cache, hash, data) + data = containers.write(fonts.otf.cache(), hash, data) else logs.error("load otf","loading failed (table conversion error)") end @@ -1160,7 +1160,7 @@ end --~ }, function fonts.otf.enhance.before(data,filename) - local private = 0xE000 + local private = fonts.private if data.subfonts and table.is_empty(data.glyphs) then local cidinfo = data.cidinfo if cidinfo.registry then @@ -1697,7 +1697,7 @@ function fonts.otf.otf_to_tfm(specification) local format = specification.format local features = specification.features.normal local cache_id = specification.hash - local tfmdata = containers.read(fonts.tfm.cache,cache_id) + local tfmdata = containers.read(fonts.tfm.cache(),cache_id) if not tfmdata then local otfdata = fonts.otf.load(filename,format,sub,features and features.featurefile) if not table.is_empty(otfdata) then @@ -1732,7 +1732,7 @@ function fonts.otf.otf_to_tfm(specification) fonts.otf.set_features(tfmdata) end end - containers.write(fonts.tfm.cache,cache_id,tfmdata) + containers.write(fonts.tfm.cache(),cache_id,tfmdata) end return tfmdata end @@ -3326,7 +3326,8 @@ do local trace = fonts.otf.trace_kerns local factor = tfmdata.factor while next and next.id == glyph and next.subtype<256 and next.font == currentfont do - if characters[next.char].description.class == 'mark' then + local cn = characters[next.char] + if not cn or cn.description.class == 'mark' then prev = next next = next.next else diff --git a/tex/context/base/font-syn.lua b/tex/context/base/font-syn.lua index 24456e7eb..d99177716 100644 --- a/tex/context/base/font-syn.lua +++ b/tex/context/base/font-syn.lua @@ -204,13 +204,13 @@ end function fonts.names.load(reload) if not fonts.names.loaded then if reload then - if containers.is_usable(fonts.names.cache, "names") then + if containers.is_usable(fonts.names.cache(), "names") then fonts.names.identify() - containers.write(fonts.names.cache, "names", fonts.names.data) + containers.write(fonts.names.cache(), "names", fonts.names.data) end fonts.names.saved = true else - fonts.names.data = containers.read(fonts.names.cache, "names") + fonts.names.data = containers.read(fonts.names.cache(), "names") if not fonts.names.saved then if table.is_empty(fonts.names.data) or table.is_empty(fonts.names.data.mapping) then fonts.names.load(true) diff --git a/tex/context/base/font-tfm.lua b/tex/context/base/font-tfm.lua index 175dd6d10..d0a838bcd 100644 --- a/tex/context/base/font-tfm.lua +++ b/tex/context/base/font-tfm.lua @@ -180,8 +180,10 @@ in the process; numbers are of course copies. Here 65536 equals 1pt. (Due to excessive memory usage in CJK fonts, we no longer pass the boundingbox.)</p> --ldx]]-- +fonts.trace_scaling = false + function fonts.tfm.do_scale(tfmtable, scaledpoints) - local trace = fonts.trace + local trace = fonts.trace_scaling if scaledpoints < 0 then scaledpoints = (- scaledpoints/1000) * tfmtable.designsize -- already in sp end @@ -463,18 +465,18 @@ do local afmdata = tfmdata.shared.afmdata local characters = tfmdata.characters local unicodes = afmdata.luatex.unicodes - local function remap(pattern,name) - local p = pattern:match(name) - if p then - local oldchr, newchr = unicodes[p], unicodes[name] - if oldchr and newchr then - characters[oldchr] = characters[newchr] + local done = false + for i, blob in pairs(characters) do + local name = blob.description.name + if name then + local p = pattern:match(name) + if p then + local oldchr, newchr = unicodes[p], unicodes[name] + if oldchr and newchr then + characters[oldchr] = characters[newchr] + end end end - return p - end - for _, blob in pairs(characters) do - remap(pattern,blob.name) end end end @@ -486,6 +488,27 @@ do fonts.initializers.common.remap(tfmdata,value,smallcaps) end + function fonts.initializers.common.fakecaps(tfmdata,value) + if value then + -- todo: scale down + local afmdata = tfmdata.shared.afmdata + local characters = tfmdata.characters + local unicodes = afmdata.luatex.unicodes + for i, blob in pairs(characters) do + local name = blob.description.name + if name then + local p = name:lower() + if p then + local oldchr, newchr = unicodes[p], unicodes[name] + if oldchr and newchr then + characters[oldchr] = characters[newchr] + end + end + end + end + end + end + end --~ function fonts.initializers.common.install(format,feature) -- 'afm','lineheight' diff --git a/tex/context/base/l-file.lua b/tex/context/base/l-file.lua index 91998532b..f49add545 100644 --- a/tex/context/base/l-file.lua +++ b/tex/context/base/l-file.lua @@ -134,14 +134,22 @@ end --~ print("../test/" .. " == " .. file.collapse_path("../test/")) --~ print("a/a" .. " == " .. file.collapse_path("a/b/c/../../a")) +--~ function file.collapse_path(str) +--~ local ok, n = false, 0 +--~ while not ok do +--~ ok = true +--~ str, n = str:gsub("[^%./]+/%.%./", function(s) +--~ ok = false +--~ return "" +--~ end) +--~ end +--~ return (str:gsub("/%./","/")) +--~ end + function file.collapse_path(str) - local ok, n = false, 0 - while not ok do - ok = true - str, n = str:gsub("[^%./]+/%.%./", function(s) - ok = false - return "" - end) + local n = 1 + while n > 0 do + str, n = str:gsub("([^/%.]+/%.%./)","") end return (str:gsub("/%./","/")) end diff --git a/tex/context/base/l-string.lua b/tex/context/base/l-string.lua index 0b2fac3a0..6a3bea31c 100644 --- a/tex/context/base/l-string.lua +++ b/tex/context/base/l-string.lua @@ -345,7 +345,6 @@ local patterns_escapes = { ["]"] = "%]", } - function string:pattesc() return (self:gsub(".",patterns_escapes)) end diff --git a/tex/context/base/l-url.lua b/tex/context/base/l-url.lua index 906ce0c0c..3bb2b1f11 100644 --- a/tex/context/base/l-url.lua +++ b/tex/context/base/l-url.lua @@ -49,7 +49,7 @@ function url.hashed(str) path = s[3], query = s[4], fragment = s[5], - original=str + original = str } end diff --git a/tex/context/base/l-utils.lua b/tex/context/base/l-utils.lua index d1faa4f34..ec8e39b94 100644 --- a/tex/context/base/l-utils.lua +++ b/tex/context/base/l-utils.lua @@ -115,19 +115,18 @@ end utils.lua.compile_strip = true -function utils.lua.compile(luafile, lucfile) +function utils.lua.compile(luafile, lucfile, cleanup) -- utils.report("compiling",luafile,"into",lucfile) os.remove(lucfile) local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile) if utils.lua.compile_strip then command = "-s " .. command end - if os.spawn("texluac " .. command) == 0 then - return true - elseif os.spawn("luac " .. command) == 0 then - return true - else - return false + local done = (os.spawn("texluac " .. command) == 0) or (os.spawn("luac " .. command) == 0) + if done and cleanup and lfs.isfile(lucfile) and lfs.isfile(luafile) then + -- utils.report("removing",luafile) + os.remove(luafile) end + return done end diff --git a/tex/context/base/l-xml.lua b/tex/context/base/l-xml.lua index 752ff3f74..b4e151ec3 100644 --- a/tex/context/base/l-xml.lua +++ b/tex/context/base/l-xml.lua @@ -480,6 +480,22 @@ do elseif not nocommands then local ec = e.command if ec ~= nil then -- we can have all kind of types + +if e.special then -- todo test for true/false + local etg, edt = e.tg, e.dt + local spc = specialconverter and specialconverter[etg] + if spc then +--~ print("SPECIAL",etg,table.serialize(specialconverter), spc) + local result = spc(edt[1]) + if result then + handle(result) + return + else + -- no need to handle any further + end + end +end + local xc = xml.command if xc then xc(e,ec) @@ -529,12 +545,18 @@ do end end end - if ern and xml.trace_remap then - if ats then - ats[#ats+1] = format("xmlns:remapped='%s'",ern) - else - ats = { format("xmlns:remapped='%s'",ern) } - end + if ern and xml.trace_remap and ern ~= ens then +--~ if ats then +--~ ats[#ats+1] = format("xmlns:remapped='%s'",ern) +--~ else +--~ ats = { format("xmlns:remapped='%s'",ern) } +--~ end +--~ if ats then +--~ ats[#ats+1] = format("remappedns='%s'",ens or '-') +--~ else +--~ ats = { format("remappedns='%s'",ens or '-') } +--~ end +ens = ern end if ens ~= "" then if edt and #edt > 0 then @@ -1115,7 +1137,7 @@ do -- way too fuzzy local found if not k or not n then - local ns, tg = root.ns, root.tg + local ns, tg = root.rn or root.ns or "", root.tg if not tg then for i=1,#root do local e = root[i] @@ -1124,10 +1146,10 @@ do break end end - elseif ns == "" then - return tg - else + elseif ns ~= "" then return ns .. ":" .. tg + else + return tg end elseif n == 0 then local e = root[k] @@ -1161,7 +1183,7 @@ do end end if found then - local ns, tg = found.ns, found.tg + local ns, tg = found.rn or found.ns or "", found.tg if ns ~= "" then return ns .. ":" .. tg else @@ -2149,7 +2171,7 @@ do if unicode and unicode.utf8 then xml.entities = xml.entities or { } -- xml.entities.handler == function function xml.entities.handler(e) - return format("[s]",e) + return format("[%s]",e) end local char = unicode.utf8.char diff --git a/tex/context/base/luat-crl.lua b/tex/context/base/luat-crl.lua index c0690b8af..aaf2e86a1 100644 --- a/tex/context/base/luat-crl.lua +++ b/tex/context/base/luat-crl.lua @@ -7,12 +7,11 @@ if not versions then versions = { } end versions['luat-crl'] = 1.001 if not curl then curl = { } end -curl.cachepath = caches.setpath(texmf.instance,"curl") - -curl.cached = { } +curl.cached = { } +curl.cachepath = caches.definepath(texmf.instance,"curl") function curl.fetch(protocol, name) - local cachename = curl.cachepath .. "/" .. name:gsub("[^%a%d%.]+","-") + local cachename = curl.cachepath() .. "/" .. name:gsub("[^%a%d%.]+","-") -- cachename = cachename:gsub("[\\/]", io.fileseparator) cachename = cachename:gsub("[\\]", "/") if not curl.cached[name] then diff --git a/tex/context/base/luat-env.lua b/tex/context/base/luat-env.lua index 73df7e3f1..48563e2e7 100644 --- a/tex/context/base/luat-env.lua +++ b/tex/context/base/luat-env.lua @@ -35,8 +35,8 @@ if environment.useluc == nil then environment.useluc = true end if not environment.formatname or environment.formatname == "" then if tex then environment.formatname = tex.formatname end end if not environment.jobname or environment.jobname == "" then if tex then environment.jobname = tex.jobname end end -if not environment.progname or environment.progname == "" then environment.progname = "luatex" end -if not environment.engine or environment.engine == "" then environment.engine = "context" end +if not environment.progname or environment.progname == "" then environment.progname = "context" end +if not environment.engine or environment.engine == "" then environment.engine = "luatex" end if not environment.formatname or environment.formatname == "" then environment.formatname = "cont-en" end if not environment.formatpath or environment.formatpath == "" then environment.formatpath = '.' end if not environment.enginepath or environment.enginepath == "" then environment.enginepath = '.' end diff --git a/tex/context/base/luat-inp.lua b/tex/context/base/luat-inp.lua index 9ab21000c..63dc1d904 100644 --- a/tex/context/base/luat-inp.lua +++ b/tex/context/base/luat-inp.lua @@ -8,6 +8,10 @@ -- additional functionality becomes available. We will split this -- module in components when we're done with prototyping. +-- TODO: os.getenv -> os.env[] +-- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller) +-- TODO: check escaping in find etc, too much, too slow + -- This is the first code I wrote for LuaTeX, so it needs some cleanup. -- To be considered: hash key lowercase, first entry in table filename @@ -18,9 +22,6 @@ -- Beware, loading and saving is overloaded in luat-tmp! --- todo: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller) --- todo: check escaping in find etc, too much, too slow - if not versions then versions = { } end versions['luat-inp'] = 1.001 if not environment then environment = { } end if not file then file = { } end @@ -39,6 +40,8 @@ if not input.hashers then input.hashers = { } end -- load databases if not input.generators then input.generators = { } end -- generate databases if not input.filters then input.filters = { } end -- conversion filters +local format = string.format + input.locators.notfound = { nil } input.hashers.notfound = { nil } input.generators.notfound = { nil } @@ -48,6 +51,7 @@ input.banner = nil input.verbose = false input.debug = false input.cnfname = 'texmf.cnf' +input.luaname = 'texmfcnf.lua' input.lsrname = 'ls-R' input.luasuffix = '.tma' input.lucsuffix = '.tmc' @@ -137,12 +141,14 @@ function input.reset() instance.files = { } instance.remap = { } instance.configuration = { } + instance.setup = { } instance.order = { } instance.found = { } instance.foundintrees = { } instance.kpsevars = { } instance.hashes = { } instance.cnffiles = { } + instance.luafiles = { } instance.lists = { } instance.remember = true instance.diskcache = true @@ -156,13 +162,11 @@ function input.reset() instance.allresults = false instance.pattern = nil -- lists instance.kpseonly = false -- lists - instance.cachefile = 'tmftools' instance.loadtime = 0 instance.starttime = 0 instance.stoptime = 0 instance.validfile = function(path,name) return true end instance.data = { } -- only for loading - instance.sortdata = false instance.force_suffixes = true instance.dummy_path_expr = "^!*unset/*$" instance.fakepaths = { } @@ -175,7 +179,7 @@ function input.reset() end else -- we will access os.env frequently - for k,v in pairs({'HOME','TEXMF','TEXMFCNF','SELFAUTOPARENT'}) do + for k,v in pairs({'HOME','TEXMF','TEXMFCNF'}) do local e = os.getenv(v) if e then -- input.report("setting",v,"to",input.bare_variable(e)) @@ -203,7 +207,7 @@ function input.reset_hashes(instance) instance.found = { } end -function input.bare_variable(str) +function input.bare_variable(str) -- assumes str is a string -- return string.gsub(string.gsub(string.gsub(str,"%s+$",""),'^"(.+)"$',"%1"),"^'(.+)'$","%1") return (str:gsub("\s*([\"\']?)(.+)%1\s*", "%2")) end @@ -288,7 +292,7 @@ do instance.stoptime = stoptime instance.loadtime = instance.loadtime + loadtime if report then - input.report('load time', string.format("%0.3f",loadtime)) + input.report('load time', format("%0.3f",loadtime)) end return loadtime end @@ -299,7 +303,7 @@ do end function input.elapsedtime(instance) - return string.format("%0.3f",(instance and instance.loadtime) or 0) + return format("%0.3f",(instance and instance.loadtime) or 0) end function input.report_loadtime(instance) @@ -315,15 +319,19 @@ function input.env(instance,key) end function input.osenv(instance,key) - if instance.environment[key] == nil then - local e = os.getenv(key) + local ie = instance.environment + local value = ie[key] + if value == nil then + -- local e = os.getenv(key) + local e = os.env[key] if e == nil then - instance.environment[key] = "" -- false + -- value = "" -- false else - instance.environment[key] = input.bare_variable(e) + value = input.bare_variable(e) end + ie[key] = value end - return instance.environment[key] or "" + return value or "" end -- we follow a rather traditional approach: @@ -334,66 +342,103 @@ end -- for the moment we don't expect a configuration file in a zip function input.identify_cnf(instance) + -- we no longer support treepath and rootpath (was handy for testing); + -- also we now follow the stupid route: if not set then just assume *one* + -- cnf file under texmf (i.e. distribution) if #instance.cnffiles == 0 then - if instance.treepath ~= "" then - -- this is a special purpose branch, not really used - if instance.rootpath ~= "" then - local t = instance.treepath:splitchr(',') - for k,v in ipairs(t) do - t[k] = file.join(instance.rootpath,v) + if input.env(instance,'TEXMFCNF') == "" then + local ownpath = environment.ownpath() or "." + if ownpath then + -- beware, this is tricky on my own system because at that location I do have + -- the raw tree that ends up in the zip; i.e. I cannot test this kind of mess + local function locate(filename,list) + local ownroot = input.normalize_name(file.join(ownpath,"../..")) + if not lfs.isdir(file.join(ownroot,"texmf")) then + ownroot = input.normalize_name(file.join(ownpath,"..")) + if not lfs.isdir(file.join(ownroot,"texmf")) then + input.verbose = true + input.report("error", "unable to identify cnf file") + return + end + end + local texmfcnf = file.join(ownroot,"texmf-local/web2c",filename) -- for minimals and myself + if not lfs.isfile(texmfcnf) then + texmfcnf = file.join(ownroot,"texmf/web2c",filename) + if not lfs.isfile(texmfcnf) then + input.verbose = true + input.report("error", "unable to locate",filename) + return + end + end + table.insert(list,texmfcnf) + local ie = instance.environment + if not ie['SELFAUTOPARENT'] then ie['SELFAUTOPARENT'] = ownroot end + if not ie['TEXMFCNF'] then ie['TEXMFCNF'] = file.dirname(texmfcnf) end + end + locate(input.luaname,instance.luafiles) + locate(input.cnfname,instance.cnffiles) + if #instance.luafiles == 0 and instance.cnffiles == 0 then + input.verbose = true + input.report("error", "unable to locate",filename) + os.exit() end - instance.treepath = table.concat(t,',') + -- here we also assume then TEXMF is set in the distribution, if this trickery is + -- used in the minimals, then users who don't use setuptex are on their own with + -- regards to extra trees + else + input.verbose = true + input.report("error", "unable to identify own path") + os.exit() end - local t = instance.treepath:splitchr(',') - instance.environment['TEXMF'] = input.bare_variable(instance.treepath) - instance.environment['TEXMFCNF'] = file.join(t[1] or '.','texmf/web2c') - end - if instance.rootpath ~= "" then - -- this assumes a single path, maybe do an expanded split here too - instance.environment['TEXMFCNF'] = file.join(instance.rootpath,'texmf/web2c') - instance.environment['SELFAUTOPARENT'] = instance.rootpath - end - if input.env(instance,'TEXMFCNF') ~= "" then + else local t = input.split_path(input.env(instance,'TEXMFCNF')) t = input.aux.expanded_path(instance,t) input.aux.expand_vars(instance,t) - for _,v in ipairs(t) do - table.insert(instance.cnffiles,file.join(v,input.cnfname)) - end - elseif input.env(instance,'SELFAUTOPARENT') == '.' then - table.insert(instance.cnffiles,file.join('.',input.cnfname)) - else - for _,v in ipairs({'texmf-local','texmf'}) do - table.insert(instance.cnffiles,file.join(input.env(instance,'SELFAUTOPARENT'),v,'web2c',input.cnfname)) + local function locate(filename,list) + for _,v in ipairs(t) do + local texmfcnf = input.normalize_name(file.join(v,filename)) + if lfs.isfile(texmfcnf) then + table.insert(list,texmfcnf) + end + end end + locate(input.luaname,instance.luafiles) + locate(input.cnfname,instance.cnffiles) end end end function input.load_cnf(instance) + local function loadoldconfigdata() + for _, fname in ipairs(instance.cnffiles) do + input.aux.load_cnf(instance,fname) + end + end -- instance.cnffiles contain complete names now ! if #instance.cnffiles == 0 then input.report("no cnf files found (TEXMFCNF may not be set/known)") else instance.rootpath = instance.cnffiles[1] for k,fname in ipairs(instance.cnffiles) do - instance.cnffiles[k] = fname:gsub("\\",'/') -- needed? + instance.cnffiles[k] = input.normalize_name(fname:gsub("\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end + instance.rootpath = input.normalize_name(instance.rootpath) + instance.environment['SELFAUTOPARENT'] = instance.rootpath -- just to be sure if instance.lsrmode then - input.loadconfigdata(instance,instance.cnffiles) + loadoldconfigdata() elseif instance.diskcache and not instance.renewcache then - input.loadconfig(instance,instance.cnffiles) + input.loadoldconfig(instance,instance.cnffiles) if instance.loaderror then - input.loadconfigdata(instance,instance.cnffiles) - input.saveconfig(instance) + loadoldconfigdata() + input.saveoldconfig(instance) end else - input.loadconfigdata(instance,instance.cnffiles) + loadoldconfigdata() if instance.renewcache then - input.saveconfig(instance) + input.saveoldconfig(instance) end end input.aux.collapse_cnf_data(instance) @@ -401,40 +446,34 @@ function input.load_cnf(instance) input.checkconfigdata(instance) end -function input.loadconfigdata(instance) - for _, fname in ipairs(instance.cnffiles) do - input.aux.load_cnf(instance,fname) +function input.load_lua(instance) + if #instance.luafiles == 0 then + -- yet harmless + else + instance.rootpath = instance.luafiles[1] + for k,fname in ipairs(instance.luafiles) do + instance.luafiles[k] = input.normalize_name(fname:gsub("\\",'/')) + end + for i=1,3 do + instance.rootpath = file.dirname(instance.rootpath) + end + instance.rootpath = input.normalize_name(instance.rootpath) + instance.environment['SELFAUTOPARENT'] = instance.rootpath -- just to be sure + input.loadnewconfig(instance) + input.aux.collapse_cnf_data(instance) end + input.checkconfigdata(instance) end -if os.env then - function input.aux.collapse_cnf_data(instance) - for _,c in ipairs(instance.order) do - for k,v in pairs(c) do - if not instance.variables[k] then - if instance.environment[k] then - instance.variables[k] = instance.environment[k] - else - instance.kpsevars[k] = true - instance.variables[k] = input.bare_variable(v) - end - end - end - end - end -else - function input.aux.collapse_cnf_data(instance) - for _,c in ipairs(instance.order) do - for k,v in pairs(c) do - if not instance.variables[k] then - local e = os.getenv(k) - if e then - instance.environment[k] = input.bare_variable(e) - instance.variables[k] = instance.environment[k] - else - instance.variables[k] = input.bare_variable(v) - instance.kpsevars[k] = true - end +function input.aux.collapse_cnf_data(instance) -- potential optmization: pass start index (setup and configuration are shared) + for _,c in ipairs(instance.order) do + for k,v in pairs(c) do + if not instance.variables[k] then + if instance.environment[k] then + instance.variables[k] = instance.environment[k] + else + instance.kpsevars[k] = true + instance.variables[k] = input.bare_variable(v) end end end @@ -445,11 +484,11 @@ function input.aux.load_cnf(instance,fname) fname = input.clean_path(fname) local lname = fname:gsub("%.%a+$",input.luasuffix) local f = io.open(lname) - if f then + if f then -- this will go f:close() local dname = file.dirname(fname) if not instance.configuration[dname] then - input.aux.load_data(instance,dname,'configuration',file.basename(lname)) + input.aux.load_configuration(instance,dname,lname) instance.order[#instance.order+1] = instance.configuration[dname] end else @@ -464,7 +503,7 @@ function input.aux.load_cnf(instance,fname) end local data = instance.configuration[dname] while true do - line = f:read() + local line, n = f:read(), 0 if line then while true do -- join lines line, n = line:gsub("\\%s*$", "") @@ -475,7 +514,7 @@ function input.aux.load_cnf(instance,fname) end end if not line:find("^[%%#]") then - k, v = (line:gsub("%s*%%.*$","")):match("%s*(.-)%s*=%s*(.-)%s*$") + local k, v = (line:gsub("%s*%%.*$","")):match("%s*(.-)%s*=%s*(.-)%s*$") if k and v and not data[k] then data[k] = (v:gsub("[%%#].*",'')):gsub("~", "$HOME") instance.kpsevars[k] = true @@ -549,6 +588,7 @@ end function input.locatelists(instance) for _, path in pairs(input.simplified_list(input.expansion(instance,'TEXMF'))) do + path = file.collapse_path(path) input.report("locating list of",path) input.locatedatabase(instance,input.normalize_name(path)) end @@ -585,7 +625,7 @@ function input.loadfiles(instance) end function input.hashers.tex(instance,tag,name) - input.aux.load_data(instance,tag,'files') + input.aux.load_files(instance,tag) end -- generators: @@ -662,7 +702,7 @@ do end end action() - input.report(string.format("%s files found on %s directories with %s uppercase remappings",n,m,r)) + input.report(format("%s files found on %s directories with %s uppercase remappings",n,m,r)) else local fullname = file.join(specification,input.lsrname) local path = '.' @@ -715,7 +755,7 @@ end -- is more convenient. function input.splitconfig(instance) - for i,c in ipairs(instance.order) do + for i,c in ipairs(instance) do for k,v in pairs(c) do if type(v) == 'string' then local t = file.split_path(v) @@ -749,14 +789,7 @@ function input.join_path(str) return str end end ---~ function input.splitexpansions(instance) ---~ for k,v in pairs(instance.expansions) do ---~ local t = file.split_path(v) ---~ if #t > 1 then ---~ instance.expansions[k] = t ---~ end ---~ end ---~ end + function input.splitexpansions(instance) for k,v in pairs(instance.expansions) do local t, h = { }, { } @@ -776,7 +809,7 @@ end -- end of split/join code -function input.saveconfig(instance) +function input.saveoldconfig(instance) input.splitconfig(instance) input.aux.save_data(instance, 'configuration', nil) input.joinconfig(instance) @@ -789,44 +822,83 @@ input.configbanner = [[ -- not copyrighted. [HH & TH] ]] -function input.aux.save_data(instance, dataname, check) - for cachename, files in pairs(instance[dataname]) do - local name = file.join(cachename,dataname) - local luaname, lucname = name .. input.luasuffix, name .. input.lucsuffix - local f = io.open(luaname,'w') - if f then - input.report("saving " .. dataname .. " in", luaname) - f:write(input.configbanner) - f:write("\n") - f:write("if not texmf then texmf = { } end\n") - f:write("if not texmf.data then texmf.data = { } end\n") - f:write("\n") - f:write("texmf.data.type = '" .. dataname .. "'\n") - f:write("texmf.data.version = '" .. input.cacheversion .. "'\n") - f:write("texmf.data.date = '" .. os.date("%Y-%m-%d") .. "'\n") - f:write("texmf.data.time = '" .. os.date("%H:%M:%S") .. "'\n") - f:write('texmf.data.content = {\n') - local function dump(k,v) - if not check or check(v,k) then -- path, name - if type(v) == 'string' then - f:write("\t['" .. k .. "'] = '" .. v .. "',\n") - elseif #v == 1 then - f:write("\t['" .. k .. "'] = '" .. v[1] .. "',\n") - else - f:write("\t['" .. k .. "'] = {'" .. table.concat(v,"','").. "'},\n") - end +function input.serialize(files) + -- This version is somewhat optimized for the kind of + -- tables that we deal with, so it's much faster than + -- the generic serializer. This makes sense because + -- luatools and mtxtools are called frequently. Okay, + -- we pay a small price for properly tabbed tables. + local t = { } + local concat = table.concat + local sorted = table.sortedkeys + local function dump(k,v,m) + if type(v) == 'string' then + return m .. "['" .. k .. "']='" .. v .. "'," + elseif #v == 1 then + return m .. "['" .. k .. "']='" .. v[1] .. "'," + else + return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'}," + end + end + t[#t+1] = "return {" + if instance.sortdata then + for _, k in pairs(sorted(files)) do + local fk = files[k] + if type(fk) == 'table' then + t[#t+1] = "\t['" .. k .. "']={" + for _, kk in pairs(sorted(fk)) do + t[#t+1] = dump(kk,fk[kk],"\t\t") end + t[#t+1] = "\t}," + else + t[#t+1] = dump(k,fk,"\t") end - if instance.sortdata then - for _, k in pairs(table.sortedkeys(files)) do - dump(k,files[k]) + end + else + for k, v in pairs(files) do + if type(v) == 'table' then + t[#t+1] = "\t['" .. k .. "']={" + for kk,vv in pairs(v) do + t[#t+1] = dump(kk,vv,"\t\t") end + t[#t+1] = "\t}," else - for k, v in pairs(files) do - dump(k,v) + t[#t+1] = dump(k,v,"\t") + end + end + end + t[#t+1] = "}" + return concat(t,"\n") +end + +if not texmf then texmf = {} end -- no longer needed, at least not here + +function input.aux.save_data(instance, dataname, check, makename) -- untested without cache overload + for cachename, files in pairs(instance[dataname]) do + local name = (makename or file.join)(cachename,dataname) + local luaname, lucname = name .. input.luasuffix, name .. input.lucsuffix + input.report("preparing " .. dataname .. " for", luaname) + for k, v in pairs(files) do + if not check or check(v,k) then -- path, name + if type(v) == "table" and #v == 1 then + files[k] = v[1] end + else + files[k] = nil -- false end - f:write('}\n') + end + local data = { + type = dataname, + root = cachename, + version = input.cacheversion, + date = os.date("%Y-%m-%d"), + time = os.date("%H:%M:%S"), + content = files, + } + local f = io.open(luaname,'w') + if f then + input.report("saving " .. dataname .. " in", luaname) + f:write(input.serialize(data)) f:close() input.report("compiling " .. dataname .. " to", lucname) if not utils.lua.compile(luaname,lucname) then @@ -839,49 +911,106 @@ function input.aux.save_data(instance, dataname, check) end end -function input.loadconfig(instance) - instance.configuration, instance.order, instance.loaderror = { }, { }, false - if not instance.renewcache then - for _, cnf in ipairs(instance.cnffiles) do - local dname = file.dirname(cnf) - input.aux.load_data(instance,dname,'configuration') - instance.order[#instance.order+1] = instance.configuration[dname] - if instance.loaderror then break end +function input.aux.load_data(instance,pathname,dataname,filename,makename) -- untested without cache overload + filename = ((not filename or (filename == "")) and dataname) or filename + filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) + local blob = loadfile(filename .. input.lucsuffix) or loadfile(filename .. input.luasuffix) + if blob then + local data = blob() + if data and data.content and data.type == dataname and data.version == input.cacheversion then + input.report("loading",dataname,"for",pathname,"from",filename) + instance[dataname][pathname] = data.content + else + input.report("skipping",dataname,"for",pathname,"from",filename) + instance[dataname][pathname] = { } + instance.loaderror = true end + else + input.report("skipping",dataname,"for",pathname,"from",filename) end - input.joinconfig(instance) end -if not texmf then texmf = {} end -if not texmf.data then texmf.data = {} end +-- some day i'll use the nested approach, but not yet (actually we even drop +-- engine/progname support since we have only luatex now) +-- +-- first texmfcnf.lua files are located, next the cached texmf.cnf files +-- +-- return { +-- TEXMFBOGUS = 'effe checken of dit werkt', +-- } -function input.aux.load_data(instance,pathname,dataname,filename) - if not filename or (filename == "") then - filename = dataname .. input.lucsuffix - end - local blob = loadfile(file.join(pathname,filename)) - if not blob then - filename = dataname .. input.luasuffix - blob = loadfile(file.join(pathname,filename)) - end +function input.aux.load_texmfcnf(instance,dataname,pathname) + local filename = file.join(pathname,input.luaname) + local blob = loadfile(filename) if blob then - blob() - if (texmf.data.type == dataname) and (texmf.data.version == input.cacheversion) and texmf.data.content then - input.report("loading",dataname,"for",pathname,"from",filename) - instance[dataname][pathname] = texmf.data.content + local data = blob() + if data then + input.report("loading","configuration file",filename) + if true then + -- flatten to variable.progname + local t = { } + for k, v in pairs(data) do -- v = progname + if type(v) == "string" then + t[k] = v + else + for kk, vv in pairs(v) do -- vv = variable + if type(vv) == "string" then + t[vv.."."..v] = kk + end + end + end + end + instance[dataname][pathname] = t + else + instance[dataname][pathname] = data + end else - input.report("skipping",dataname,"for",pathname,"from",filename) + input.report("skipping","configuration file",filename) instance[dataname][pathname] = { } instance.loaderror = true end + else + input.report("skipping","configuration file",filename) + end +end + +function input.aux.load_configuration(instance,dname,lname) + input.aux.load_data(instance,dname,'configuration',lname and file.basename(lname)) +end +function input.aux.load_files(instance,tag) + input.aux.load_data(instance,tag,'files') +end + +function input.resetconfig(instance) + instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false +end + +function input.loadnewconfig(instance) + for _, cnf in ipairs(instance.luafiles) do + local dname = file.dirname(cnf) + input.aux.load_texmfcnf(instance,'setup',dname) + instance.order[#instance.order+1] = instance.setup[dname] + if instance.loaderror then break end end - texmf.data.content = { } +end + +function input.loadoldconfig(instance) + if not instance.renewcache then + for _, cnf in ipairs(instance.cnffiles) do + local dname = file.dirname(cnf) + input.aux.load_configuration(instance,dname) + instance.order[#instance.order+1] = instance.configuration[dname] + if instance.loaderror then break end + end + end + input.joinconfig(instance) end function input.expand_variables(instance) instance.expansions = { } - if instance.engine ~= "" then instance.environment['engine'] = instance.engine end - if instance.progname ~= "" then instance.environment['progname'] = instance.engine end +--~ instance.environment['SELFAUTOPARENT'] = instance.environment['SELFAUTOPARENT'] or instance.rootpath + if instance.engine ~= "" then instance.environment['engine'] = instance.engine end + if instance.progname ~= "" then instance.environment['progname'] = instance.progname end for k,v in pairs(instance.environment) do local a, b = k:match("^(%a+)%_(.*)%s*$") if a and b then @@ -972,53 +1101,6 @@ function input.is_expansion(instance,name) return input.aux.is_entry(instance,instance.expansions,name) end -function input.aux.list(instance,list) - local pat = string.upper(instance.pattern or "","") - for _,key in pairs(table.sortedkeys(list)) do - if (instance.pattern=="") or string.find(key:upper(),pat) then - if instance.kpseonly then - if instance.kpsevars[key] then - print(key .. "=" .. input.aux.tabstr(list[key])) - end - elseif instance.kpsevars[key] then - print('K ' .. key .. "=" .. input.aux.tabstr(list[key])) - else - print('E ' .. key .. "=" .. input.aux.tabstr(list[key])) - end - end - end -end - -function input.list_variables(instance) - input.aux.list(instance,instance.variables) -end -function input.list_expansions(instance) - input.aux.list(instance,instance.expansions) -end - -function input.list_configurations(instance) - for _,key in pairs(table.sortedkeys(instance.kpsevars)) do - if not instance.pattern or (instance.pattern=="") or key:find(instance.pattern) then - print(key.."\n") - for i,c in ipairs(instance.order) do - local str = c[key] - if str then - print("\t" .. i .. "\t\t" .. input.aux.tabstr(str)) - end - end - print() - end - end -end - -function input.aux.tabstr(str) - if type(str) == 'table' then - return table.concat(str," | ") - else - return str - end -end - function input.simplified_list(str) if type(str) == 'table' then return str -- troubles ; ipv , in texmf @@ -1042,23 +1124,6 @@ function input.unexpanded_path(instance,str) return file.join_path(input.unexpanded_path_list(instance,str)) end ---~ function input.expanded_path_list(instance,str) ---~ if not str then ---~ return { } ---~ elseif instance.savelists then ---~ -- engine+progname hash ---~ str = str:gsub("%$","") ---~ if not instance.lists[str] then -- cached ---~ local lst = input.split_path(input.expansion(instance,str)) ---~ instance.lists[str] = input.aux.expanded_path(instance,lst) ---~ end ---~ return instance.lists[str] ---~ else ---~ local lst = input.split_path(input.expansion(instance,str)) ---~ return input.aux.expanded_path(instance,lst) ---~ end ---~ end - do local done = { } @@ -1471,6 +1536,8 @@ do return original end + input.normalize_name = file.collapse_path + end function input.aux.register_in_trees(instance,name) @@ -1836,7 +1903,10 @@ end function input.load(instance) input.starttiming(instance) + input.resetconfig(instance) input.identify_cnf(instance) + input.load_lua(instance) + input.expand_variables(instance) input.load_cnf(instance) input.expand_variables(instance) input.load_hash(instance) diff --git a/tex/context/base/luat-lib.lua b/tex/context/base/luat-lib.lua index 0b18f3eeb..c3c66f7d8 100644 --- a/tex/context/base/luat-lib.lua +++ b/tex/context/base/luat-lib.lua @@ -33,14 +33,32 @@ os.platform = os.platform or os.type or (io.pathseparator == ";" and "windows") -- -- for k,v in pairs(arg) do print(k,v) end -if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then - arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil -end - -- environment if not environment then environment = { } end +environment.ownbin = environment.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex" + +local ownpath = nil -- we could use a metatable here + +function environment.ownpath() + if not ownpath then + for p in string.gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do + local b = file.join(p,environment.ownbin) + if lfs.isfile(b..".exe") or lfs.isfile(b) then + ownpath = p + break + end + end + if not ownpath then ownpath = '.' end + end + return ownpath +end + +if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then + arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil +end + environment.arguments = { } environment.files = { } environment.sorted_argument_keys = nil diff --git a/tex/context/base/luat-tex.lua b/tex/context/base/luat-tex.lua index c241bcf80..c9d99c48a 100644 --- a/tex/context/base/luat-tex.lua +++ b/tex/context/base/luat-tex.lua @@ -293,7 +293,6 @@ if texconfig and not texlua then if not texmf.instance then -- prevent a second loading - texmf.instance = input.reset() texmf.instance.progname = environment.progname or 'context' texmf.instance.engine = environment.engine or 'luatex' diff --git a/tex/context/base/luat-tmp.lua b/tex/context/base/luat-tmp.lua index b4583133f..f3b062353 100644 --- a/tex/context/base/luat-tmp.lua +++ b/tex/context/base/luat-tmp.lua @@ -32,28 +32,45 @@ caches.more = caches.more or "context" caches.direct = false -- true is faster but may need huge amounts of memory caches.trace = false caches.tree = false -caches.temp = caches.temp or os.getenv("TEXMFCACHE") or os.getenv("HOME") or os.getenv("HOMEPATH") or os.getenv("VARTEXMF") or os.getenv("TEXMFVAR") or os.getenv("TMP") or os.getenv("TEMP") or os.getenv("TMPDIR") or nil -caches.paths = caches.paths or { caches.temp } +caches.paths = caches.paths or nil caches.force = false input.usecache = not toboolean(os.getenv("TEXMFSHARECACHE") or "false",true) -- true -if caches.temp and caches.temp ~= "" and lfs.attributes(caches.temp,"mode") ~= "directory" then - if caches.force or io.ask(string.format("Should I create the cache path %s?",caches.temp), "no", { "yes", "no" }) == "yes" then - dir.mkdirs(caches.temp) +function caches.temp(instance) + local function checkpath(cachepath) + if not cachepath or cachepath == "" then + return nil + elseif lfs.attributes(cachepath,"mode") == "directory" then -- lfs.isdir(cachepath) then + return cachepath + elseif caches.force or io.ask(string.format("Should I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then + dir.mkdirs(cachepath) + return (lfs.attributes(cachepath,"mode") == "directory") and cachepath + else + return nil + end end -end -if not caches.temp or caches.temp == "" then - print("\nfatal error: there is no valid cache path defined\n") - os.exit() -elseif lfs.attributes(caches.temp,"mode") ~= "directory" then - print(string.format("\nfatal error: cache path %s is not a directory\n",caches.temp)) - os.exit() + local cachepath = input.expanded_path_list(instance,"TEXMFCACHE") + cachepath = cachepath and #cachepath > 0 and checkpath(cachepath[1]) + if not cachepath then + cachepath = os.getenv("TEXMFCACHE") or os.getenv("HOME") or os.getenv("HOMEPATH") or os.getenv("TMP") or os.getenv("TEMP") or os.getenv("TMPDIR") or nil + cachepath = checkpath(cachepath) + end + if not cachepath then + print("\nfatal error: there is no valid cache path defined\n") + os.exit() + elseif lfs.attributes(cachepath,"mode") ~= "directory" then + print(string.format("\nfatal error: cache path %s is not a directory\n",cachepath)) + os.exit() + end + function caches.temp(instance) + return cachepath + end + return cachepath end function caches.configpath(instance) return table.concat(instance.cnffiles,";") ---~ return input.expand_var(instance,"TEXMFCNF") end function caches.hashed(tree) @@ -71,19 +88,8 @@ end function caches.setpath(instance,...) if not caches.path then - if lfs and instance then - for _,v in pairs(caches.paths) do - for _,vv in pairs(input.expanded_path_list(instance,v)) do - if lfs.isdir(vv) then - caches.path = vv - break - end - end - if caches.path then break end - end - end if not caches.path then - caches.path = caches.temp + caches.path = caches.temp(instance) end caches.path = input.clean_path(caches.path) -- to be sure if lfs then @@ -107,6 +113,12 @@ function caches.setpath(instance,...) return caches.path end +function caches.definepath(instance,category,subcategory) + return function() + return caches.setpath(instance,category,subcategory) + end +end + function caches.setluanames(path,name) return path .. "/" .. name .. ".tma", path .. "/" .. name .. ".tmc" end @@ -135,9 +147,9 @@ function caches.savedata(filepath,filename,data,raw) -- raw needed for file cach if caches.direct then file.savedata(tmaname, table.serialize(data,'return',true,true)) else - table.tofile (tmaname, data,'return',true,true) -- maybe not the last true + table.tofile(tmaname, data,'return',true,true) -- maybe not the last true end - utils.lua.compile(tmaname, tmcname) + utils.lua.compile(tmaname, tmcname, input.expand_var(texmf.instance,'PURGECACHE') == 't') end -- here we use the cache for format loading (texconfig.[formatname|jobname]) @@ -172,19 +184,35 @@ do -- local report end end + local allocated = { } + + -- tracing + function containers.define(category, subcategory, version, enabled) - if category and subcategory then - return { - category = category, - subcategory = subcategory, - storage = { }, - enabled = enabled, - version = version or 1.000, - trace = false, - path = caches.setpath(texmf.instance,category,subcategory), - } - else - return nil + return function() + if category and subcategory then + local c = allocated[category] + if not c then + c = { } + allocated[category] = c + end + local s = c[subcategory] + if not s then + s = { + category = category, + subcategory = subcategory, + storage = { }, + enabled = enabled, + version = version or 1.000, + trace = false, + path = caches.setpath(texmf.instance,category,subcategory), + } + c[subcategory] = s + end + return s + else + return nil + end end end @@ -241,129 +269,35 @@ end -- since we want to use the cache instead of the tree, we will now -- reimplement the saver. +local save_data = input.aux.save_data + +input.cachepath = nil + function input.aux.save_data(instance, dataname, check) - for cachename, files in pairs(instance[dataname]) do - local name + input.cachepath = input.cachepath or caches.definepath(instance,"trees") + save_data(instance, dataname, check, function(cachename,dataname) if input.usecache then - name = file.join(caches.setpath(instance,"trees"),caches.hashed(cachename)) + return file.join(input.cachepath(),caches.hashed(cachename)) else - name = file.join(cachename,dataname) + return file.join(cachename,dataname) end - local luaname, lucname = name .. input.luasuffix, name .. input.lucsuffix - input.report("preparing " .. dataname .. " in", luaname) - for k, v in pairs(files) do - if not check or check(v,k) then -- path, name - if type(v) == "table" and #v == 1 then - files[k] = v[1] - end - else - files[k] = nil -- false - end - end - local data = { - type = dataname, - root = cachename, - version = input.cacheversion, - date = os.date("%Y-%m-%d"), - time = os.date("%H:%M:%S"), - content = files, - } - local f = io.open(luaname,'w') - if f then - input.report("saving " .. dataname .. " in", luaname) - -- f:write(table.serialize(data,'return')) - f:write(input.serialize(data)) - f:close() - input.report("compiling " .. dataname .. " to", lucname) - if not utils.lua.compile(luaname,lucname) then - input.report("compiling failed for " .. dataname .. ", deleting file " .. lucname) - os.remove(lucname) - end - else - input.report("unable to save " .. dataname .. " in " .. name..input.luasuffix) - end - end + end) end -function input.serialize(files) - -- This version is somewhat optimized for the kind of - -- tables that we deal with, so it's much faster than - -- the generic serializer. This makes sense because - -- luatools and mtxtools are called frequently. Okay, - -- we pay a small price for properly tabbed tables. - local t = { } - local concat = table.concat - local sorted = table.sortedkeys - local function dump(k,v,m) - if type(v) == 'string' then - return m .. "['" .. k .. "']='" .. v .. "'," - elseif #v == 1 then - return m .. "['" .. k .. "']='" .. v[1] .. "'," - else - return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'}," - end - end - t[#t+1] = "return {" - if instance.sortdata then - for _, k in pairs(sorted(files)) do - local fk = files[k] - if type(fk) == 'table' then - t[#t+1] = "\t['" .. k .. "']={" - for _, kk in pairs(sorted(fk)) do - t[#t+1] = dump(kk,fk[kk],"\t\t") - end - t[#t+1] = "\t}," - else - t[#t+1] = dump(k,fk,"\t") - end - end - else - for k, v in pairs(files) do - if type(v) == 'table' then - t[#t+1] = "\t['" .. k .. "']={" - for kk,vv in pairs(v) do - t[#t+1] = dump(kk,vv,"\t\t") - end - t[#t+1] = "\t}," - else - t[#t+1] = dump(k,v,"\t") - end - end - end - t[#t+1] = "}" - return concat(t,"\n") -end +local load_data = input.aux.load_data function input.aux.load_data(instance,pathname,dataname,filename) - local luaname, lucname, pname, fname - if input.usecache then - pname, fname = caches.setpath(instance,"trees"), caches.hashed(pathname) - filename = file.join(pname,fname) - else - if not filename or (filename == "") then - filename = dataname - end - pname, fname = pathname, filename - end - luaname = file.join(pname,fname) .. input.luasuffix - lucname = file.join(pname,fname) .. input.lucsuffix - local blob = loadfile(lucname) - if not blob then - blob = loadfile(luaname) - end - if blob then - local data = blob() - if data and data.content and data.type == dataname and data.version == input.cacheversion then - input.report("loading",dataname,"for",pathname,"from",filename) - instance[dataname][pathname] = data.content + input.cachepath = input.cachepath or caches.definepath(instance,"trees") + load_data(instance,pathname,dataname,filename,function(dataname,filename) + if input.usecache then + return file.join(input.cachepath(),caches.hashed(pathname)) else - input.report("skipping",dataname,"for",pathname,"from",filename) - instance[dataname][pathname] = { } - instance.loaderror = true + if not filename or (filename == "") then + filename = dataname + end + return file.join(pathname,filename) end - else - input.report("skipping",dataname,"for",pathname,"from",filename) - end + end) end -- we will make a better format, maybe something xml or just text or lua diff --git a/tex/context/base/lxml-ini.lua b/tex/context/base/lxml-ini.lua index 2f2a74b38..f6dba95d4 100644 --- a/tex/context/base/lxml-ini.lua +++ b/tex/context/base/lxml-ini.lua @@ -15,6 +15,8 @@ local type, next, tonumber = type, next, tonumber document = document or { } document.xml = document.xml or { } +-- todo: loaded and myself per document so that we can garbage collect buffers + lxml = { } lxml.loaded = { } lxml.myself = { } @@ -61,7 +63,7 @@ do -- quit else local tr = type(root) - if tr == "string" then + if tr == "string" then -- can also be result of lpath capture:match(root) elseif tr == "table" then serialize(root,sprint,nil,nil,specialhandler) @@ -99,7 +101,6 @@ do end end - -- lines (untested) local buffer = { } @@ -161,7 +162,7 @@ do local root = get_id(id) if before then texsprint(tex.ctxcatcodes,format("%s[%s]",before,root.tg)) end serialize(root.dt,toverbatim,nil,nil,nil,true) -- was root - if after then texsprint(tex.ctxcatcodes,after) end + if after then texsprint(tex.ctxcatcodes,after) end end function lxml.inlineverbatim(id) lxml.verbatim(id,"\\startxmlinlineverbatim","\\stopxmlinlineverbatim") @@ -170,6 +171,33 @@ do lxml.verbatim(id,"\\startxmldisplayverbatim","\\stopxmldisplayverbatim") end + local pihandlers = { } + + specialhandler['@pi@'] = function(str) + for i=1,#pihandlers do + pihandlers[i](str) + end + end + + xml.pihandlers = pihandlers + + local kind = lpeg.P("context-") * lpeg.C((1-lpeg.P("-"))^1) * lpeg.P("-directive") + local space = lpeg.S(" \n\r") + local spaces = space^0 + local class = lpeg.C((1-space)^0) + local key = class + local value = lpeg.C(lpeg.P(1-(space * -1))^0) + + local parser = kind * spaces * class * spaces * key * spaces * value + + pihandlers[#pihandlers+1] = function(str) + -- local kind, class, key, value = parser:match(str) + texsprint(tex.ctxcatcodes,format("\\xmlcontextdirective{%s}{%s}{%s}{%s}",parser:match(str))) + end + + -- print(contextdirective("context-mathml-directive function reduction yes yes ")) + -- print(contextdirective("context-mathml-directive function ")) + end local xmlsprint = xml.sprint @@ -284,8 +312,9 @@ function lxml.count(id,pattern) end function lxml.name(id) -- or remapped name? -> lxml.info, combine local r = get_id(id) - if r.ns then - texsprint(r.ns .. ":" .. r.tg) + local ns = t.rn or r.ns or "" + if ns ~= "" then + texsprint(ns .. ":" .. r.tg) else texsprint(r.tg) end @@ -313,9 +342,9 @@ function lxml.concatrange(id,what,start,stop,separator,lastseparator) -- test th if i == #t then -- nothing elseif i == #t-1 and lastseparator ~= "" then - tex.sprint(tex.ctxcatcodes,lastseparator) + texsprint(tex.ctxcatcodes,lastseparator) elseif separator ~= "" then - tex.sprint(tex.ctxcatcodes,separator) + texsprint(tex.ctxcatcodes,separator) end end end @@ -367,7 +396,7 @@ lxml.trace_setups = false function lxml.setsetup(id,pattern,setup) local trace = lxml.trace_setups - if not setup or setup == "" or setup == "*" or setup == "-" then + if not setup or setup == "" or setup == "*" or setup == "-" or setup == "+" then for rt, dt, dk in xmlelements(get_id(id),pattern) do local dtdk = dt and dt[dk] or rt local ns, tg = dtdk.rn or dtdk.ns, dtdk.tg @@ -594,16 +623,29 @@ do end function xml.getbuffer(name) -- we need to make sure that commands are processed + if not name or name == "" then + name = tex.jobname + end xml.tostring(xml.convert(concat(buffers.data[name] or {},""))) end function lxml.loadbuffer(id,name) + if not name or name == "" then + name = tex.jobname + end input.starttiming(xml) - loaded[id] = xml.convert(concat(buffers.data[name or id] or {},"")) + loaded[id] = xml.convert(buffers.collect(name or id,"\n")) input.stoptiming(xml) return loaded[id], name or id end +function lxml.loaddata(id,str) + input.starttiming(xml) + loaded[id] = xml.convert(str or "") + input.stoptiming(xml) + return loaded[id], id +end + -- for the moment here: lxml.set_verbatim("\\xmlcdatabefore", "\\xmlcdataafter", "\\xmlcdataobeyedline", "\\xmlcdataobeyedspace") diff --git a/tex/context/base/lxml-ini.tex b/tex/context/base/lxml-ini.tex index 8d01736a1..c6cd60b89 100644 --- a/tex/context/base/lxml-ini.tex +++ b/tex/context/base/lxml-ini.tex @@ -42,6 +42,7 @@ \def\xmllast #1#2{\ctxlua{lxml.last("#1","#2")}} \def\xmlload #1#2{\ctxlua{lxml.load("#1","#2")}} \def\xmlloadbuffer #1#2{\ctxlua{lxml.loadbuffer("#1","#2")}} +\def\xmlloaddata #1#2{\ctxlua{lxml.loaddata("#1",\!!bs#2\!!es)}} \def\xmlloaddirectives #1{\ctxlua{lxml.directives.load("#1")}} \def\xmlname #1{\ctxlua{lxml.name("#1")}} \def\xmlnamespace #1{\ctxlua{lxml.namespace("#1")}} @@ -120,8 +121,10 @@ {\directsetup{#4}}% \endgroup} -\def\xmlprocess {\doxmlprocess\xmlload} +\def\xmlprocessfile {\doxmlprocess\xmlload} +\def\xmlprocessdata {\doxmlprocess\xmlloaddata} \def\xmlprocessbuffer{\doxmlprocess\xmlloadbuffer} +\let\xmlprocess \xmlprocessfile \startsetups xml:process \xmlregisteredsetups @@ -207,7 +210,14 @@ {\ctxlua{xml.set_text_cleanup(lxml.trace_text_entities)}% \appendtoks\ctxlua{lxml.show_text_entities()}\to\everygoodbye} +% processing instructions + +\def\xmlcontextdirective#1% kind class key value + {\executeifdefined{xml#1directive}\gobblethreearguments} + % brrrr, give this at the top of a style that needs to stub mkiv loading +% +% this will change \def\processXMLfileMKIV {\dosingleempty\doprocessXMLfileMKIV} diff --git a/tex/context/base/math-ent.lua b/tex/context/base/math-ent.lua new file mode 100644 index 000000000..7cc45b8a2 --- /dev/null +++ b/tex/context/base/math-ent.lua @@ -0,0 +1,2097 @@ +if not modules then modules = { } end modules ['math-ent'] = { + version = 1.001, + comment = "companion to math-ini.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "derived from the mathml 2.0 specification", +} + +math.entities={ + ["Aacute"]=0x000C1, + ["aacute"]=0x000E1, + ["Abreve"]=0x00102, + ["abreve"]=0x00103, + ["ac"]=0x0223E, + ["acd"]=0x0223F, + ["acE"]=0x0223E, + ["Acirc"]=0x000C2, + ["acirc"]=0x000E2, + ["acute"]=0x000B4, + ["Acy"]=0x00410, + ["acy"]=0x00430, + ["AElig"]=0x000C6, + ["aelig"]=0x000E6, + ["af"]=0x02061, + ["Afr"]=0x1D504, + ["afr"]=0x1D51E, + ["Agrave"]=0x000C0, + ["agrave"]=0x000E0, + ["aleph"]=0x02135, + ["alpha"]=0x003B1, + ["Amacr"]=0x00100, + ["amacr"]=0x00101, + ["amalg"]=0x02A3F, + ["amp"]=0x00026, + ["And"]=0x02A53, + ["and"]=0x02227, + ["andand"]=0x02A55, + ["andd"]=0x02A5C, + ["andslope"]=0x02A58, + ["andv"]=0x02A5A, + ["ang"]=0x02220, + ["ange"]=0x029A4, + ["angle"]=0x02220, + ["angmsd"]=0x02221, + ["angmsdaa"]=0x029A8, + ["angmsdab"]=0x029A9, + ["angmsdac"]=0x029AA, + ["angmsdad"]=0x029AB, + ["angmsdae"]=0x029AC, + ["angmsdaf"]=0x029AD, + ["angmsdag"]=0x029AE, + ["angmsdah"]=0x029AF, + ["angrt"]=0x0221F, + ["angrtvb"]=0x022BE, + ["angrtvbd"]=0x0299D, + ["angsph"]=0x02222, + ["angst"]=0x0212B, + ["angzarr"]=0x0237C, + ["Aogon"]=0x00104, + ["aogon"]=0x00105, + ["Aopf"]=0x1D538, + ["aopf"]=0x1D552, + ["ap"]=0x02248, + ["apacir"]=0x02A6F, + ["apE"]=0x02A70, + ["ape"]=0x0224A, + ["apid"]=0x0224B, + ["apos"]=0x00027, + ["ApplyFunction"]=0x02061, + ["approx"]=0x02248, + ["approxeq"]=0x0224A, + ["Aring"]=0x000C5, + ["aring"]=0x000E5, + ["Ascr"]=0x1D49C, + ["ascr"]=0x1D4B6, + ["Assign"]=0x02254, + ["ast"]=0x0002A, + ["asymp"]=0x02248, + ["asympeq"]=0x0224D, + ["Atilde"]=0x000C3, + ["atilde"]=0x000E3, + ["Auml"]=0x000C4, + ["auml"]=0x000E4, + ["awconint"]=0x02233, + ["awint"]=0x02A11, + ["backcong"]=0x0224C, + ["backepsilon"]=0x003F6, + ["backprime"]=0x02035, + ["backsim"]=0x0223D, + ["backsimeq"]=0x022CD, + ["Backslash"]=0x02216, + ["Barv"]=0x02AE7, + ["barvee"]=0x022BD, + ["Barwed"]=0x02306, + ["barwed"]=0x02305, + ["barwedge"]=0x02305, + ["bbrk"]=0x023B5, + ["bbrktbrk"]=0x023B6, + ["bcong"]=0x0224C, + ["Bcy"]=0x00411, + ["bcy"]=0x00431, + ["becaus"]=0x02235, + ["Because"]=0x02235, + ["because"]=0x02235, + ["bemptyv"]=0x029B0, + ["bepsi"]=0x003F6, + ["bernou"]=0x0212C, + ["Bernoullis"]=0x0212C, + ["beta"]=0x003B2, + ["beth"]=0x02136, + ["between"]=0x0226C, + ["Bfr"]=0x1D505, + ["bfr"]=0x1D51F, + ["bigcap"]=0x022C2, + ["bigcirc"]=0x025EF, + ["bigcup"]=0x022C3, + ["bigodot"]=0x02A00, + ["bigoplus"]=0x02A01, + ["bigotimes"]=0x02A02, + ["bigsqcup"]=0x02A06, + ["bigstar"]=0x02605, + ["bigtriangledown"]=0x025BD, + ["bigtriangleup"]=0x025B3, + ["biguplus"]=0x02A04, + ["bigvee"]=0x022C1, + ["bigwedge"]=0x022C0, + ["bkarow"]=0x0290D, + ["blacklozenge"]=0x029EB, + ["blacksquare"]=0x025AA, + ["blacktriangle"]=0x025B4, + ["blacktriangledown"]=0x025BE, + ["blacktriangleleft"]=0x025C2, + ["blacktriangleright"]=0x025B8, + ["blank"]=0x02423, + ["blk12"]=0x02592, + ["blk14"]=0x02591, + ["blk34"]=0x02593, + ["block"]=0x02588, + ["bne"]=0x0003D, + ["bnequiv"]=0x02261, + ["bNot"]=0x02AED, + ["bnot"]=0x02310, + ["Bopf"]=0x1D539, + ["bopf"]=0x1D553, + ["bot"]=0x022A5, + ["bottom"]=0x022A5, + ["bowtie"]=0x022C8, + ["boxbox"]=0x029C9, + ["boxDL"]=0x02557, + ["boxDl"]=0x02556, + ["boxdL"]=0x02555, + ["boxdl"]=0x02510, + ["boxDR"]=0x02554, + ["boxDr"]=0x02553, + ["boxdR"]=0x02552, + ["boxdr"]=0x0250C, + ["boxH"]=0x02550, + ["boxh"]=0x02500, + ["boxHD"]=0x02566, + ["boxHd"]=0x02564, + ["boxhD"]=0x02565, + ["boxhd"]=0x0252C, + ["boxHU"]=0x02569, + ["boxHu"]=0x02567, + ["boxhU"]=0x02568, + ["boxhu"]=0x02534, + ["boxminus"]=0x0229F, + ["boxplus"]=0x0229E, + ["boxtimes"]=0x022A0, + ["boxUL"]=0x0255D, + ["boxUl"]=0x0255C, + ["boxuL"]=0x0255B, + ["boxul"]=0x02518, + ["boxUR"]=0x0255A, + ["boxUr"]=0x02559, + ["boxuR"]=0x02558, + ["boxur"]=0x02514, + ["boxV"]=0x02551, + ["boxv"]=0x02502, + ["boxVH"]=0x0256C, + ["boxVh"]=0x0256B, + ["boxvH"]=0x0256A, + ["boxvh"]=0x0253C, + ["boxVL"]=0x02563, + ["boxVl"]=0x02562, + ["boxvL"]=0x02561, + ["boxvl"]=0x02524, + ["boxVR"]=0x02560, + ["boxVr"]=0x0255F, + ["boxvR"]=0x0255E, + ["boxvr"]=0x0251C, + ["bprime"]=0x02035, + ["Breve"]=0x002D8, + ["breve"]=0x002D8, + ["brvbar"]=0x000A6, + ["Bscr"]=0x0212C, + ["bscr"]=0x1D4B7, + ["bsemi"]=0x0204F, + ["bsim"]=0x0223D, + ["bsime"]=0x022CD, + ["bsol"]=0x0005C, + ["bsolb"]=0x029C5, + ["bsolhsub"]=0x0005C, + ["bull"]=0x02022, + ["bullet"]=0x02022, + ["bump"]=0x0224E, + ["bumpE"]=0x02AAE, + ["bumpe"]=0x0224F, + ["Bumpeq"]=0x0224E, + ["bumpeq"]=0x0224F, + ["Cacute"]=0x00106, + ["cacute"]=0x00107, + ["Cap"]=0x022D2, + ["cap"]=0x02229, + ["capand"]=0x02A44, + ["capbrcup"]=0x02A49, + ["capcap"]=0x02A4B, + ["capcup"]=0x02A47, + ["capdot"]=0x02A40, + ["CapitalDifferentialD"]=0x02145, + ["caps"]=0x02229, + ["caret"]=0x02041, + ["caron"]=0x002C7, + ["Cayleys"]=0x0212D, + ["ccaps"]=0x02A4D, + ["Ccaron"]=0x0010C, + ["ccaron"]=0x0010D, + ["Ccedil"]=0x000C7, + ["ccedil"]=0x000E7, + ["Ccirc"]=0x00108, + ["ccirc"]=0x00109, + ["Cconint"]=0x02230, + ["ccups"]=0x02A4C, + ["ccupssm"]=0x02A50, + ["Cdot"]=0x0010A, + ["cdot"]=0x0010B, + ["cedil"]=0x000B8, + ["Cedilla"]=0x000B8, + ["cemptyv"]=0x029B2, + ["cent"]=0x000A2, + ["CenterDot"]=0x000B7, + ["centerdot"]=0x000B7, + ["Cfr"]=0x0212D, + ["cfr"]=0x1D520, + ["CHcy"]=0x00427, + ["chcy"]=0x00447, + ["check"]=0x02713, + ["checkmark"]=0x02713, + ["chi"]=0x003C7, + ["cir"]=0x025CB, + ["circ"]=0x002C6, + ["circeq"]=0x02257, + ["circlearrowleft"]=0x021BA, + ["circlearrowright"]=0x021BB, + ["circledast"]=0x0229B, + ["circledcirc"]=0x0229A, + ["circleddash"]=0x0229D, + ["CircleDot"]=0x02299, + ["circledR"]=0x000AE, + ["circledS"]=0x024C8, + ["CircleMinus"]=0x02296, + ["CirclePlus"]=0x02295, + ["CircleTimes"]=0x02297, + ["cirE"]=0x029C3, + ["cire"]=0x02257, + ["cirfnint"]=0x02A10, + ["cirmid"]=0x02AEF, + ["cirscir"]=0x029C2, + ["ClockwiseContourIntegral"]=0x02232, + ["CloseCurlyDoubleQuote"]=0x0201D, + ["CloseCurlyQuote"]=0x02019, + ["clubs"]=0x02663, + ["clubsuit"]=0x02663, + ["Colon"]=0x02237, + ["colon"]=0x0003A, + ["Colone"]=0x02A74, + ["colone"]=0x02254, + ["coloneq"]=0x02254, + ["comma"]=0x0002C, + ["commat"]=0x00040, + ["comp"]=0x02201, + ["compfn"]=0x02218, + ["complement"]=0x02201, + ["complexes"]=0x02102, + ["cong"]=0x02245, + ["congdot"]=0x02A6D, + ["Congruent"]=0x02261, + ["Conint"]=0x0222F, + ["conint"]=0x0222E, + ["ContourIntegral"]=0x0222E, + ["Copf"]=0x02102, + ["copf"]=0x1D554, + ["coprod"]=0x02210, + ["Coproduct"]=0x02210, + ["copy"]=0x000A9, + ["copysr"]=0x02117, + ["CounterClockwiseContourIntegral"]=0x02233, + ["Cross"]=0x02A2F, + ["cross"]=0x02717, + ["Cscr"]=0x1D49E, + ["cscr"]=0x1D4B8, + ["csub"]=0x02ACF, + ["csube"]=0x02AD1, + ["csup"]=0x02AD0, + ["csupe"]=0x02AD2, + ["ctdot"]=0x022EF, + ["cudarrl"]=0x02938, + ["cudarrr"]=0x02935, + ["cuepr"]=0x022DE, + ["cuesc"]=0x022DF, + ["cularr"]=0x021B6, + ["cularrp"]=0x0293D, + ["Cup"]=0x022D3, + ["cup"]=0x0222A, + ["cupbrcap"]=0x02A48, + ["CupCap"]=0x0224D, + ["cupcap"]=0x02A46, + ["cupcup"]=0x02A4A, + ["cupdot"]=0x0228D, + ["cupor"]=0x02A45, + ["cups"]=0x0222A, + ["curarr"]=0x021B7, + ["curarrm"]=0x0293C, + ["curlyeqprec"]=0x022DE, + ["curlyeqsucc"]=0x022DF, + ["curlyvee"]=0x022CE, + ["curlywedge"]=0x022CF, + ["curren"]=0x000A4, + ["curvearrowleft"]=0x021B6, + ["curvearrowright"]=0x021B7, + ["cuvee"]=0x022CE, + ["cuwed"]=0x022CF, + ["cwconint"]=0x02232, + ["cwint"]=0x02231, + ["cylcty"]=0x0232D, + ["Dagger"]=0x02021, + ["Dagger"]=0x02021, + ["dagger"]=0x02020, + ["dagger"]=0x02020, + ["daleth"]=0x02138, + ["Darr"]=0x021A1, + ["dArr"]=0x021D3, + ["darr"]=0x02193, + ["dash"]=0x02010, + ["Dashv"]=0x02AE4, + ["dashv"]=0x022A3, + ["dbkarow"]=0x0290F, + ["dblac"]=0x002DD, + ["Dcaron"]=0x0010E, + ["dcaron"]=0x0010F, + ["Dcy"]=0x00414, + ["dcy"]=0x00434, + ["DD"]=0x02145, + ["dd"]=0x02146, + ["ddagger"]=0x02021, + ["ddarr"]=0x021CA, + ["DDotrahd"]=0x02911, + ["ddotseq"]=0x02A77, + ["deg"]=0x000B0, + ["Del"]=0x02207, + ["Delta"]=0x00394, + ["delta"]=0x003B4, + ["demptyv"]=0x029B1, + ["dfisht"]=0x0297F, + ["Dfr"]=0x1D507, + ["dfr"]=0x1D521, + ["dHar"]=0x02965, + ["dharl"]=0x021C3, + ["dharr"]=0x021C2, + ["DiacriticalAcute"]=0x000B4, + ["DiacriticalDot"]=0x002D9, + ["DiacriticalDoubleAcute"]=0x002DD, + ["DiacriticalGrave"]=0x00060, + ["DiacriticalTilde"]=0x002DC, + ["diam"]=0x022C4, + ["Diamond"]=0x022C4, + ["diamond"]=0x022C4, + ["diamondsuit"]=0x02666, + ["diams"]=0x02666, + ["die"]=0x000A8, + ["DifferentialD"]=0x02146, + ["digamma"]=0x003DD, + ["disin"]=0x022F2, + ["div"]=0x000F7, + ["divide"]=0x000F7, + ["divideontimes"]=0x022C7, + ["divonx"]=0x022C7, + ["DJcy"]=0x00402, + ["djcy"]=0x00452, + ["dlcorn"]=0x0231E, + ["dlcrop"]=0x0230D, + ["dollar"]=0x00024, + ["Dopf"]=0x1D53B, + ["dopf"]=0x1D555, + ["Dot"]=0x000A8, + ["dot"]=0x002D9, + ["DotDot"]=0x020DC, + ["doteq"]=0x02250, + ["doteqdot"]=0x02251, + ["DotEqual"]=0x02250, + ["dotminus"]=0x02238, + ["dotplus"]=0x02214, + ["dotsquare"]=0x022A1, + ["doublebarwedge"]=0x02306, + ["DoubleContourIntegral"]=0x0222F, + ["DoubleDot"]=0x000A8, + ["DoubleDownArrow"]=0x021D3, + ["DoubleLeftArrow"]=0x021D0, + ["DoubleLeftRightArrow"]=0x021D4, + ["DoubleLeftTee"]=0x02AE4, + ["DoubleLongLeftArrow"]=0x027F8, + ["DoubleLongLeftRightArrow"]=0x027FA, + ["DoubleLongRightArrow"]=0x027F9, + ["DoubleRightArrow"]=0x021D2, + ["DoubleRightTee"]=0x022A8, + ["DoubleUpArrow"]=0x021D1, + ["DoubleUpDownArrow"]=0x021D5, + ["DoubleVerticalBar"]=0x02225, + ["DownArrow"]=0x02193, + ["Downarrow"]=0x021D3, + ["downarrow"]=0x02193, + ["DownArrowBar"]=0x02913, + ["DownArrowUpArrow"]=0x021F5, + ["DownBreve"]=0x00311, + ["downdownarrows"]=0x021CA, + ["downharpoonleft"]=0x021C3, + ["downharpoonright"]=0x021C2, + ["DownLeftRightVector"]=0x02950, + ["DownLeftTeeVector"]=0x0295E, + ["DownLeftVector"]=0x021BD, + ["DownLeftVectorBar"]=0x02956, + ["DownRightTeeVector"]=0x0295F, + ["DownRightVector"]=0x021C1, + ["DownRightVectorBar"]=0x02957, + ["DownTee"]=0x022A4, + ["DownTeeArrow"]=0x021A7, + ["drbkarow"]=0x02910, + ["drcorn"]=0x0231F, + ["drcrop"]=0x0230C, + ["Dscr"]=0x1D49F, + ["dscr"]=0x1D4B9, + ["DScy"]=0x00405, + ["dscy"]=0x00455, + ["dsol"]=0x029F6, + ["Dstrok"]=0x00110, + ["dstrok"]=0x00111, + ["dtdot"]=0x022F1, + ["dtri"]=0x025BF, + ["dtrif"]=0x025BE, + ["duarr"]=0x021F5, + ["duhar"]=0x0296F, + ["dwangle"]=0x029A6, + ["DZcy"]=0x0040F, + ["dzcy"]=0x0045F, + ["dzigrarr"]=0x027FF, + ["Eacute"]=0x000C9, + ["eacute"]=0x000E9, + ["easter"]=0x02A6E, + ["Ecaron"]=0x0011A, + ["ecaron"]=0x0011B, + ["ecir"]=0x02256, + ["Ecirc"]=0x000CA, + ["ecirc"]=0x000EA, + ["ecolon"]=0x02255, + ["Ecy"]=0x0042D, + ["ecy"]=0x0044D, + ["eDDot"]=0x02A77, + ["Edot"]=0x00116, + ["eDot"]=0x02251, + ["edot"]=0x00117, + ["ee"]=0x02147, + ["efDot"]=0x02252, + ["Efr"]=0x1D508, + ["efr"]=0x1D522, + ["eg"]=0x02A9A, + ["Egrave"]=0x000C8, + ["egrave"]=0x000E8, + ["egs"]=0x02A96, + ["egsdot"]=0x02A98, + ["el"]=0x02A99, + ["Element"]=0x02208, + ["elinters"]=0x0FFFD, + ["ell"]=0x02113, + ["els"]=0x02A95, + ["elsdot"]=0x02A97, + ["Emacr"]=0x00112, + ["emacr"]=0x00113, + ["empty"]=0x02205, + ["emptyset"]=0x02205, + ["EmptySmallSquare"]=0x025FB, + ["emptyv"]=0x02205, + ["EmptyVerySmallSquare"]=0x025AB, + ["emsp"]=0x02003, + ["emsp13"]=0x02004, + ["emsp14"]=0x02005, + ["ENG"]=0x0014A, + ["eng"]=0x0014B, + ["ensp"]=0x02002, + ["Eogon"]=0x00118, + ["eogon"]=0x00119, + ["Eopf"]=0x1D53C, + ["eopf"]=0x1D556, + ["epar"]=0x022D5, + ["eparsl"]=0x029E3, + ["eplus"]=0x02A71, + ["epsi"]=0x003F5, + ["epsiv"]=0x003B5, + ["eqcirc"]=0x02256, + ["eqcolon"]=0x02255, + ["eqsim"]=0x02242, + ["eqslantgtr"]=0x02A96, + ["eqslantless"]=0x02A95, + ["Equal"]=0x02A75, + ["equals"]=0x0003D, + ["EqualTilde"]=0x02242, + ["equest"]=0x0225F, + ["Equilibrium"]=0x021CC, + ["equiv"]=0x02261, + ["equivDD"]=0x02A78, + ["eqvparsl"]=0x029E5, + ["erarr"]=0x02971, + ["erDot"]=0x02253, + ["Escr"]=0x02130, + ["escr"]=0x0212F, + ["esdot"]=0x02250, + ["Esim"]=0x02A73, + ["esim"]=0x02242, + ["eta"]=0x003B7, + ["ETH"]=0x000D0, + ["eth"]=0x000F0, + ["Euml"]=0x000CB, + ["euml"]=0x000EB, + ["excl"]=0x00021, + ["exist"]=0x02203, + ["Exists"]=0x02203, + ["expectation"]=0x02130, + ["ExponentialE"]=0x02147, + ["exponentiale"]=0x02147, + ["fallingdotseq"]=0x02252, + ["Fcy"]=0x00424, + ["fcy"]=0x00444, + ["female"]=0x02640, + ["ffilig"]=0x0FB03, + ["fflig"]=0x0FB00, + ["ffllig"]=0x0FB04, + ["Ffr"]=0x1D509, + ["ffr"]=0x1D523, + ["filig"]=0x0FB01, + ["FilledSmallSquare"]=0x025FC, + ["FilledVerySmallSquare"]=0x025AA, + ["flat"]=0x0266D, + ["fllig"]=0x0FB02, + ["fltns"]=0x025B1, + ["fnof"]=0x00192, + ["Fopf"]=0x1D53D, + ["fopf"]=0x1D557, + ["ForAll"]=0x02200, + ["forall"]=0x02200, + ["fork"]=0x022D4, + ["forkv"]=0x02AD9, + ["Fouriertrf"]=0x02131, + ["fpartint"]=0x02A0D, + ["frac12"]=0x000BD, + ["frac13"]=0x02153, + ["frac14"]=0x000BC, + ["frac15"]=0x02155, + ["frac16"]=0x02159, + ["frac18"]=0x0215B, + ["frac23"]=0x02154, + ["frac25"]=0x02156, + ["frac34"]=0x000BE, + ["frac35"]=0x02157, + ["frac38"]=0x0215C, + ["frac45"]=0x02158, + ["frac56"]=0x0215A, + ["frac58"]=0x0215D, + ["frac78"]=0x0215E, + ["frown"]=0x02322, + ["Fscr"]=0x02131, + ["fscr"]=0x1D4BB, + ["gacute"]=0x001F5, + ["Gamma"]=0x00393, + ["gamma"]=0x003B3, + ["Gammad"]=0x003DC, + ["gammad"]=0x003DD, + ["gap"]=0x02A86, + ["Gbreve"]=0x0011E, + ["gbreve"]=0x0011F, + ["Gcedil"]=0x00122, + ["Gcirc"]=0x0011C, + ["gcirc"]=0x0011D, + ["Gcy"]=0x00413, + ["gcy"]=0x00433, + ["Gdot"]=0x00120, + ["gdot"]=0x00121, + ["gE"]=0x02267, + ["ge"]=0x02265, + ["gEl"]=0x02A8C, + ["gel"]=0x022DB, + ["geq"]=0x02265, + ["geqq"]=0x02267, + ["geqslant"]=0x02A7E, + ["ges"]=0x02A7E, + ["gescc"]=0x02AA9, + ["gesdot"]=0x02A80, + ["gesdoto"]=0x02A82, + ["gesdotol"]=0x02A84, + ["gesl"]=0x022DB, + ["gesles"]=0x02A94, + ["Gfr"]=0x1D50A, + ["gfr"]=0x1D524, + ["Gg"]=0x022D9, + ["gg"]=0x0226B, + ["ggg"]=0x022D9, + ["gimel"]=0x02137, + ["GJcy"]=0x00403, + ["gjcy"]=0x00453, + ["gl"]=0x02277, + ["gla"]=0x02AA5, + ["glE"]=0x02A92, + ["glj"]=0x02AA4, + ["gnap"]=0x02A8A, + ["gnapprox"]=0x02A8A, + ["gnE"]=0x02269, + ["gne"]=0x02A88, + ["gneq"]=0x02A88, + ["gneqq"]=0x02269, + ["gnsim"]=0x022E7, + ["Gopf"]=0x1D53E, + ["gopf"]=0x1D558, + ["grave"]=0x00060, + ["GreaterEqual"]=0x02265, + ["GreaterEqualLess"]=0x022DB, + ["GreaterFullEqual"]=0x02267, + ["GreaterGreater"]=0x02AA2, + ["GreaterLess"]=0x02277, + ["GreaterSlantEqual"]=0x02A7E, + ["GreaterTilde"]=0x02273, + ["Gscr"]=0x1D4A2, + ["gscr"]=0x0210A, + ["gsim"]=0x02273, + ["gsime"]=0x02A8E, + ["gsiml"]=0x02A90, + ["Gt"]=0x0226B, + ["gt"]=0x0003E, + ["gtcc"]=0x02AA7, + ["gtcir"]=0x02A7A, + ["gtdot"]=0x022D7, + ["gtlPar"]=0x02995, + ["gtquest"]=0x02A7C, + ["gtrapprox"]=0x02A86, + ["gtrarr"]=0x02978, + ["gtrdot"]=0x022D7, + ["gtreqless"]=0x022DB, + ["gtreqqless"]=0x02A8C, + ["gtrless"]=0x02277, + ["gtrsim"]=0x02273, + ["gvertneqq"]=0x02269, + ["gvnE"]=0x02269, + ["Hacek"]=0x002C7, + ["hairsp"]=0x0200A, + ["half"]=0x000BD, + ["hamilt"]=0x0210B, + ["HARDcy"]=0x0042A, + ["hardcy"]=0x0044A, + ["hArr"]=0x021D4, + ["harr"]=0x02194, + ["harrcir"]=0x02948, + ["harrw"]=0x021AD, + ["Hat"]=0x0005E, + ["hbar"]=0x0210F, + ["Hcirc"]=0x00124, + ["hcirc"]=0x00125, + ["hearts"]=0x02665, + ["heartsuit"]=0x02665, + ["hellip"]=0x02026, + ["hercon"]=0x022B9, + ["Hfr"]=0x0210C, + ["hfr"]=0x1D525, + ["HilbertSpace"]=0x0210B, + ["hksearow"]=0x02925, + ["hkswarow"]=0x02926, + ["hoarr"]=0x021FF, + ["homtht"]=0x0223B, + ["hookleftarrow"]=0x021A9, + ["hookrightarrow"]=0x021AA, + ["Hopf"]=0x0210D, + ["hopf"]=0x1D559, + ["horbar"]=0x02015, + ["HorizontalLine"]=0x02500, + ["Hscr"]=0x0210B, + ["hscr"]=0x1D4BD, + ["hslash"]=0x0210F, + ["Hstrok"]=0x00126, + ["hstrok"]=0x00127, + ["HumpDownHump"]=0x0224E, + ["HumpEqual"]=0x0224F, + ["hybull"]=0x02043, + ["hyphen"]=0x02010, + ["Iacute"]=0x000CD, + ["iacute"]=0x000ED, + ["ic"]=0x02063, + ["Icirc"]=0x000CE, + ["icirc"]=0x000EE, + ["Icy"]=0x00418, + ["icy"]=0x00438, + ["Idot"]=0x00130, + ["IEcy"]=0x00415, + ["iecy"]=0x00435, + ["iexcl"]=0x000A1, + ["iff"]=0x021D4, + ["Ifr"]=0x02111, + ["ifr"]=0x1D526, + ["Igrave"]=0x000CC, + ["igrave"]=0x000EC, + ["ii"]=0x02148, + ["iiiint"]=0x02A0C, + ["iiint"]=0x0222D, + ["iinfin"]=0x029DC, + ["iiota"]=0x02129, + ["IJlig"]=0x00132, + ["ijlig"]=0x00133, + ["Im"]=0x02111, + ["Imacr"]=0x0012A, + ["imacr"]=0x0012B, + ["image"]=0x02111, + ["ImaginaryI"]=0x02148, + ["imagline"]=0x02110, + ["imagpart"]=0x02111, + ["imath"]=0x00131, + ["imof"]=0x022B7, + ["imped"]=0x001B5, + ["Implies"]=0x021D2, + ["in"]=0x02208, + ["incare"]=0x02105, + ["infin"]=0x0221E, + ["infintie"]=0x029DD, + ["inodot"]=0x00131, + ["Int"]=0x0222C, + ["int"]=0x0222B, + ["intcal"]=0x022BA, + ["integers"]=0x02124, + ["Integral"]=0x0222B, + ["intercal"]=0x022BA, + ["Intersection"]=0x022C2, + ["intlarhk"]=0x02A17, + ["intprod"]=0x02A3C, + ["InvisibleComma"]=0x02063, + ["InvisibleTimes"]=0x02062, + ["IOcy"]=0x00401, + ["iocy"]=0x00451, + ["Iogon"]=0x0012E, + ["iogon"]=0x0012F, + ["Iopf"]=0x1D540, + ["iopf"]=0x1D55A, + ["iota"]=0x003B9, + ["iprod"]=0x02A3C, + ["iquest"]=0x000BF, + ["Iscr"]=0x02110, + ["iscr"]=0x1D4BE, + ["isin"]=0x02208, + ["isindot"]=0x022F5, + ["isinE"]=0x022F9, + ["isins"]=0x022F4, + ["isinsv"]=0x022F3, + ["isinv"]=0x02208, + ["it"]=0x02062, + ["Itilde"]=0x00128, + ["itilde"]=0x00129, + ["Iukcy"]=0x00406, + ["iukcy"]=0x00456, + ["Iuml"]=0x000CF, + ["iuml"]=0x000EF, + ["Jcirc"]=0x00134, + ["jcirc"]=0x00135, + ["Jcy"]=0x00419, + ["jcy"]=0x00439, + ["Jfr"]=0x1D50D, + ["jfr"]=0x1D527, + ["jmath"]=0x0006A, + ["Jopf"]=0x1D541, + ["jopf"]=0x1D55B, + ["Jscr"]=0x1D4A5, + ["jscr"]=0x1D4BF, + ["Jsercy"]=0x00408, + ["jsercy"]=0x00458, + ["Jukcy"]=0x00404, + ["jukcy"]=0x00454, + ["kappa"]=0x003BA, + ["kappav"]=0x003F0, + ["Kcedil"]=0x00136, + ["kcedil"]=0x00137, + ["Kcy"]=0x0041A, + ["kcy"]=0x0043A, + ["Kfr"]=0x1D50E, + ["kfr"]=0x1D528, + ["kgreen"]=0x00138, + ["KHcy"]=0x00425, + ["khcy"]=0x00445, + ["KJcy"]=0x0040C, + ["kjcy"]=0x0045C, + ["Kopf"]=0x1D542, + ["kopf"]=0x1D55C, + ["Kscr"]=0x1D4A6, + ["kscr"]=0x1D4C0, + ["lAarr"]=0x021DA, + ["Lacute"]=0x00139, + ["lacute"]=0x0013A, + ["laemptyv"]=0x029B4, + ["lagran"]=0x02112, + ["Lambda"]=0x0039B, + ["lambda"]=0x003BB, + ["Lang"]=0x0300A, + ["lang"]=0x02329, + ["langd"]=0x02991, + ["langle"]=0x02329, + ["lap"]=0x02A85, + ["Laplacetrf"]=0x02112, + ["laquo"]=0x000AB, + ["Larr"]=0x0219E, + ["lArr"]=0x021D0, + ["larr"]=0x02190, + ["larrb"]=0x021E4, + ["larrbfs"]=0x0291F, + ["larrfs"]=0x0291D, + ["larrhk"]=0x021A9, + ["larrlp"]=0x021AB, + ["larrpl"]=0x02939, + ["larrsim"]=0x02973, + ["larrtl"]=0x021A2, + ["lat"]=0x02AAB, + ["lAtail"]=0x0291B, + ["latail"]=0x02919, + ["late"]=0x02AAD, + ["lates"]=0x02AAD, + ["lBarr"]=0x0290E, + ["lbarr"]=0x0290C, + ["lbbrk"]=0x03014, + ["lbrace"]=0x0007B, + ["lbrack"]=0x0005B, + ["lbrke"]=0x0298B, + ["lbrksld"]=0x0298F, + ["lbrkslu"]=0x0298D, + ["Lcaron"]=0x0013D, + ["lcaron"]=0x0013E, + ["Lcedil"]=0x0013B, + ["lcedil"]=0x0013C, + ["lceil"]=0x02308, + ["lcub"]=0x0007B, + ["Lcy"]=0x0041B, + ["lcy"]=0x0043B, + ["ldca"]=0x02936, + ["ldquo"]=0x0201C, + ["ldquor"]=0x0201E, + ["ldrdhar"]=0x02967, + ["ldrushar"]=0x0294B, + ["ldsh"]=0x021B2, + ["lE"]=0x02266, + ["le"]=0x02264, + ["LeftAngleBracket"]=0x02329, + ["LeftArrow"]=0x02190, + ["Leftarrow"]=0x021D0, + ["leftarrow"]=0x02190, + ["LeftArrowBar"]=0x021E4, + ["LeftArrowRightArrow"]=0x021C6, + ["leftarrowtail"]=0x021A2, + ["LeftCeiling"]=0x02308, + ["LeftDoubleBracket"]=0x0301A, + ["LeftDownTeeVector"]=0x02961, + ["LeftDownVector"]=0x021C3, + ["LeftDownVectorBar"]=0x02959, + ["LeftFloor"]=0x0230A, + ["leftharpoondown"]=0x021BD, + ["leftharpoonup"]=0x021BC, + ["leftleftarrows"]=0x021C7, + ["LeftRightArrow"]=0x02194, + ["Leftrightarrow"]=0x021D4, + ["leftrightarrow"]=0x02194, + ["leftrightarrows"]=0x021C6, + ["leftrightharpoons"]=0x021CB, + ["leftrightsquigarrow"]=0x021AD, + ["LeftRightVector"]=0x0294E, + ["LeftTee"]=0x022A3, + ["LeftTeeArrow"]=0x021A4, + ["LeftTeeVector"]=0x0295A, + ["leftthreetimes"]=0x022CB, + ["LeftTriangle"]=0x022B2, + ["LeftTriangleBar"]=0x029CF, + ["LeftTriangleEqual"]=0x022B4, + ["LeftUpDownVector"]=0x02951, + ["LeftUpTeeVector"]=0x02960, + ["LeftUpVector"]=0x021BF, + ["LeftUpVectorBar"]=0x02958, + ["LeftVector"]=0x021BC, + ["LeftVectorBar"]=0x02952, + ["lEg"]=0x02A8B, + ["leg"]=0x022DA, + ["leq"]=0x02264, + ["leqq"]=0x02266, + ["leqslant"]=0x02A7D, + ["les"]=0x02A7D, + ["lescc"]=0x02AA8, + ["lesdot"]=0x02A7F, + ["lesdoto"]=0x02A81, + ["lesdotor"]=0x02A83, + ["lesg"]=0x022DA, + ["lesges"]=0x02A93, + ["lessapprox"]=0x02A85, + ["lessdot"]=0x022D6, + ["lesseqgtr"]=0x022DA, + ["lesseqqgtr"]=0x02A8B, + ["LessEqualGreater"]=0x022DA, + ["LessFullEqual"]=0x02266, + ["LessGreater"]=0x02276, + ["lessgtr"]=0x02276, + ["LessLess"]=0x02AA1, + ["lesssim"]=0x02272, + ["LessSlantEqual"]=0x02A7D, + ["LessTilde"]=0x02272, + ["lfisht"]=0x0297C, + ["lfloor"]=0x0230A, + ["Lfr"]=0x1D50F, + ["lfr"]=0x1D529, + ["lg"]=0x02276, + ["lgE"]=0x02A91, + ["lHar"]=0x02962, + ["lhard"]=0x021BD, + ["lharu"]=0x021BC, + ["lharul"]=0x0296A, + ["lhblk"]=0x02584, + ["LJcy"]=0x00409, + ["ljcy"]=0x00459, + ["Ll"]=0x022D8, + ["ll"]=0x0226A, + ["llarr"]=0x021C7, + ["llcorner"]=0x0231E, + ["Lleftarrow"]=0x021DA, + ["llhard"]=0x0296B, + ["lltri"]=0x025FA, + ["Lmidot"]=0x0013F, + ["lmidot"]=0x00140, + ["lmoust"]=0x023B0, + ["lmoustache"]=0x023B0, + ["lnap"]=0x02A89, + ["lnapprox"]=0x02A89, + ["lnE"]=0x02268, + ["lne"]=0x02A87, + ["lneq"]=0x02A87, + ["lneqq"]=0x02268, + ["lnsim"]=0x022E6, + ["loang"]=0x03018, + ["loarr"]=0x021FD, + ["lobrk"]=0x0301A, + ["LongLeftArrow"]=0x027F5, + ["Longleftarrow"]=0x027F8, + ["longleftarrow"]=0x027F5, + ["LongLeftRightArrow"]=0x027F7, + ["Longleftrightarrow"]=0x027FA, + ["longleftrightarrow"]=0x027F7, + ["longmapsto"]=0x027FC, + ["LongRightArrow"]=0x027F6, + ["Longrightarrow"]=0x027F9, + ["longrightarrow"]=0x027F6, + ["looparrowleft"]=0x021AB, + ["looparrowright"]=0x021AC, + ["lopar"]=0x02985, + ["Lopf"]=0x1D543, + ["lopf"]=0x1D55D, + ["loplus"]=0x02A2D, + ["lotimes"]=0x02A34, + ["lowast"]=0x02217, + ["lowbar"]=0x0005F, + ["LowerLeftArrow"]=0x02199, + ["LowerRightArrow"]=0x02198, + ["loz"]=0x025CA, + ["lozenge"]=0x025CA, + ["lozf"]=0x029EB, + ["lpar"]=0x00028, + ["lparlt"]=0x02993, + ["lrarr"]=0x021C6, + ["lrcorner"]=0x0231F, + ["lrhar"]=0x021CB, + ["lrhard"]=0x0296D, + ["lrtri"]=0x022BF, + ["Lscr"]=0x02112, + ["lscr"]=0x1D4C1, + ["Lsh"]=0x021B0, + ["lsh"]=0x021B0, + ["lsim"]=0x02272, + ["lsime"]=0x02A8D, + ["lsimg"]=0x02A8F, + ["lsqb"]=0x0005B, + ["lsquo"]=0x02018, + ["lsquor"]=0x0201A, + ["Lstrok"]=0x00141, + ["lstrok"]=0x00142, + ["Lt"]=0x0226A, + ["lt"]=0x0003C, + ["ltcc"]=0x02AA6, + ["ltcir"]=0x02A79, + ["ltdot"]=0x022D6, + ["lthree"]=0x022CB, + ["ltimes"]=0x022C9, + ["ltlarr"]=0x02976, + ["ltquest"]=0x02A7B, + ["ltri"]=0x025C3, + ["ltrie"]=0x022B4, + ["ltrif"]=0x025C2, + ["ltrPar"]=0x02996, + ["lurdshar"]=0x0294A, + ["luruhar"]=0x02966, + ["lvertneqq"]=0x02268, + ["lvnE"]=0x02268, + ["macr"]=0x000AF, + ["male"]=0x02642, + ["malt"]=0x02720, + ["maltese"]=0x02720, + ["Map"]=0x02905, + ["map"]=0x021A6, + ["mapsto"]=0x021A6, + ["mapstodown"]=0x021A7, + ["mapstoleft"]=0x021A4, + ["mapstoup"]=0x021A5, + ["marker"]=0x025AE, + ["mcomma"]=0x02A29, + ["Mcy"]=0x0041C, + ["mcy"]=0x0043C, + ["mdash"]=0x02014, + ["mDDot"]=0x0223A, + ["measuredangle"]=0x02221, + ["MediumSpace"]=0x0205F, + ["Mellintrf"]=0x02133, + ["Mfr"]=0x1D510, + ["mfr"]=0x1D52A, + ["mho"]=0x02127, + ["micro"]=0x000B5, + ["mid"]=0x02223, + ["midast"]=0x0002A, + ["midcir"]=0x02AF0, + ["middot"]=0x000B7, + ["minus"]=0x02212, + ["minusb"]=0x0229F, + ["minusd"]=0x02238, + ["minusdu"]=0x02A2A, + ["MinusPlus"]=0x02213, + ["mlcp"]=0x02ADB, + ["mldr"]=0x02026, + ["mnplus"]=0x02213, + ["models"]=0x022A7, + ["Mopf"]=0x1D544, + ["mopf"]=0x1D55E, + ["mp"]=0x02213, + ["Mscr"]=0x02133, + ["mscr"]=0x1D4C2, + ["mstpos"]=0x0223E, + ["mu"]=0x003BC, + ["multimap"]=0x022B8, + ["mumap"]=0x022B8, + ["nabla"]=0x02207, + ["Nacute"]=0x00143, + ["nacute"]=0x00144, + ["nang"]=0x02220, + ["nap"]=0x02249, + ["napE"]=0x02A70, + ["napid"]=0x0224B, + ["napos"]=0x00149, + ["napprox"]=0x02249, + ["natur"]=0x0266E, + ["natural"]=0x0266E, + ["naturals"]=0x02115, + ["nbsp"]=0x000A0, + ["nbump"]=0x0224E, + ["nbumpe"]=0x0224F, + ["ncap"]=0x02A43, + ["Ncaron"]=0x00147, + ["ncaron"]=0x00148, + ["Ncedil"]=0x00145, + ["ncedil"]=0x00146, + ["ncong"]=0x02247, + ["ncongdot"]=0x02A6D, + ["ncup"]=0x02A42, + ["Ncy"]=0x0041D, + ["ncy"]=0x0043D, + ["ndash"]=0x02013, + ["ne"]=0x02260, + ["nearhk"]=0x02924, + ["neArr"]=0x021D7, + ["nearr"]=0x02197, + ["nearrow"]=0x02197, + ["nedot"]=0x02250, + ["NegativeMediumSpace"]=0x0200B, + ["NegativeThickSpace"]=0x0200B, + ["NegativeThinSpace"]=0x0200B, + ["NegativeVeryThinSpace"]=0x0200B, + ["nequiv"]=0x02262, + ["nesear"]=0x02928, + ["nesim"]=0x02242, + ["NestedGreaterGreater"]=0x0226B, + ["NestedLessLess"]=0x0226A, + ["NewLine"]=0x0000A, + ["nexist"]=0x02204, + ["nexists"]=0x02204, + ["Nfr"]=0x1D511, + ["nfr"]=0x1D52B, + ["ngE"]=0x02267, + ["nge"]=0x02271, + ["ngeq"]=0x02271, + ["ngeqq"]=0x02267, + ["ngeqslant"]=0x02A7E, + ["nges"]=0x02A7E, + ["nGg"]=0x022D9, + ["ngsim"]=0x02275, + ["nGt"]=0x0226B, + ["ngt"]=0x0226F, + ["ngtr"]=0x0226F, + ["nGtv"]=0x0226B, + ["nhArr"]=0x021CE, + ["nharr"]=0x021AE, + ["nhpar"]=0x02AF2, + ["ni"]=0x0220B, + ["nis"]=0x022FC, + ["nisd"]=0x022FA, + ["niv"]=0x0220B, + ["NJcy"]=0x0040A, + ["njcy"]=0x0045A, + ["nlArr"]=0x021CD, + ["nlarr"]=0x0219A, + ["nldr"]=0x02025, + ["nlE"]=0x02266, + ["nle"]=0x02270, + ["nLeftarrow"]=0x021CD, + ["nleftarrow"]=0x0219A, + ["nLeftrightarrow"]=0x021CE, + ["nleftrightarrow"]=0x021AE, + ["nleq"]=0x02270, + ["nleqq"]=0x02266, + ["nleqslant"]=0x02A7D, + ["nles"]=0x02A7D, + ["nless"]=0x0226E, + ["nLl"]=0x022D8, + ["nlsim"]=0x02274, + ["nLt"]=0x0226A, + ["nlt"]=0x0226E, + ["nltri"]=0x022EA, + ["nltrie"]=0x022EC, + ["nLtv"]=0x0226A, + ["nmid"]=0x02224, + ["NoBreak"]=0x02060, + ["NonBreakingSpace"]=0x000A0, + ["Nopf"]=0x02115, + ["nopf"]=0x1D55F, + ["Not"]=0x02AEC, + ["not"]=0x000AC, + ["NotCongruent"]=0x02262, + ["NotCupCap"]=0x0226D, + ["NotDoubleVerticalBar"]=0x02226, + ["NotElement"]=0x02209, + ["NotEqual"]=0x02260, + ["NotEqualTilde"]=0x02242, + ["NotExists"]=0x02204, + ["NotGreater"]=0x0226F, + ["NotGreaterEqual"]=0x02271, + ["NotGreaterFullEqual"]=0x02266, + ["NotGreaterGreater"]=0x0226B, + ["NotGreaterLess"]=0x02279, + ["NotGreaterSlantEqual"]=0x02A7E, + ["NotGreaterTilde"]=0x02275, + ["NotHumpDownHump"]=0x0224E, + ["NotHumpEqual"]=0x0224F, + ["notin"]=0x02209, + ["notindot"]=0x022F5, + ["notinE"]=0x022F9, + ["notinva"]=0x02209, + ["notinvb"]=0x022F7, + ["notinvc"]=0x022F6, + ["NotLeftTriangle"]=0x022EA, + ["NotLeftTriangleBar"]=0x029CF, + ["NotLeftTriangleEqual"]=0x022EC, + ["NotLess"]=0x0226E, + ["NotLessEqual"]=0x02270, + ["NotLessGreater"]=0x02278, + ["NotLessLess"]=0x0226A, + ["NotLessSlantEqual"]=0x02A7D, + ["NotLessTilde"]=0x02274, + ["NotNestedGreaterGreater"]=0x02AA2, + ["NotNestedLessLess"]=0x02AA1, + ["notni"]=0x0220C, + ["notniva"]=0x0220C, + ["notnivb"]=0x022FE, + ["notnivc"]=0x022FD, + ["NotPrecedes"]=0x02280, + ["NotPrecedesEqual"]=0x02AAF, + ["NotPrecedesSlantEqual"]=0x022E0, + ["NotReverseElement"]=0x0220C, + ["NotRightTriangle"]=0x022EB, + ["NotRightTriangleBar"]=0x029D0, + ["NotRightTriangleEqual"]=0x022ED, + ["NotSquareSubset"]=0x0228F, + ["NotSquareSubsetEqual"]=0x022E2, + ["NotSquareSuperset"]=0x02290, + ["NotSquareSupersetEqual"]=0x022E3, + ["NotSubset"]=0x02282, + ["NotSubsetEqual"]=0x02288, + ["NotSucceeds"]=0x02281, + ["NotSucceedsEqual"]=0x02AB0, + ["NotSucceedsSlantEqual"]=0x022E1, + ["NotSucceedsTilde"]=0x0227F, + ["NotSuperset"]=0x02283, + ["NotSupersetEqual"]=0x02289, + ["NotTilde"]=0x02241, + ["NotTildeEqual"]=0x02244, + ["NotTildeFullEqual"]=0x02247, + ["NotTildeTilde"]=0x02249, + ["NotVerticalBar"]=0x02224, + ["npar"]=0x02226, + ["nparallel"]=0x02226, + ["nparsl"]=0x02AFD, + ["npart"]=0x02202, + ["npolint"]=0x02A14, + ["npr"]=0x02280, + ["nprcue"]=0x022E0, + ["npre"]=0x02AAF, + ["nprec"]=0x02280, + ["npreceq"]=0x02AAF, + ["nrArr"]=0x021CF, + ["nrarr"]=0x0219B, + ["nrarrc"]=0x02933, + ["nrarrw"]=0x0219D, + ["nRightarrow"]=0x021CF, + ["nrightarrow"]=0x0219B, + ["nrtri"]=0x022EB, + ["nrtrie"]=0x022ED, + ["nsc"]=0x02281, + ["nsccue"]=0x022E1, + ["nsce"]=0x02AB0, + ["Nscr"]=0x1D4A9, + ["nscr"]=0x1D4C3, + ["nshortmid"]=0x02224, + ["nshortparallel"]=0x02226, + ["nsim"]=0x02241, + ["nsime"]=0x02244, + ["nsimeq"]=0x02244, + ["nsmid"]=0x02224, + ["nspar"]=0x02226, + ["nsqsube"]=0x022E2, + ["nsqsupe"]=0x022E3, + ["nsub"]=0x02284, + ["nsubE"]=0x02AC5, + ["nsube"]=0x02288, + ["nsubset"]=0x02282, + ["nsubseteq"]=0x02288, + ["nsubseteqq"]=0x02AC5, + ["nsucc"]=0x02281, + ["nsucceq"]=0x02AB0, + ["nsup"]=0x02285, + ["nsupE"]=0x02AC6, + ["nsupe"]=0x02289, + ["nsupset"]=0x02283, + ["nsupseteq"]=0x02289, + ["nsupseteqq"]=0x02AC6, + ["ntgl"]=0x02279, + ["Ntilde"]=0x000D1, + ["ntilde"]=0x000F1, + ["ntlg"]=0x02278, + ["ntriangleleft"]=0x022EA, + ["ntrianglelefteq"]=0x022EC, + ["ntriangleright"]=0x022EB, + ["ntrianglerighteq"]=0x022ED, + ["nu"]=0x003BD, + ["num"]=0x00023, + ["numero"]=0x02116, + ["numsp"]=0x02007, + ["nvap"]=0x0224D, + ["nVDash"]=0x022AF, + ["nVdash"]=0x022AE, + ["nvDash"]=0x022AD, + ["nvdash"]=0x022AC, + ["nvge"]=0x02265, + ["nvgt"]=0x0003E, + ["nvHarr"]=0x02904, + ["nvinfin"]=0x029DE, + ["nvlArr"]=0x02902, + ["nvle"]=0x02264, + ["nvlt"]=0x0003C, + ["nvltrie"]=0x022B4, + ["nvrArr"]=0x02903, + ["nvrtrie"]=0x022B5, + ["nvsim"]=0x0223C, + ["nwarhk"]=0x02923, + ["nwArr"]=0x021D6, + ["nwarr"]=0x02196, + ["nwarrow"]=0x02196, + ["nwnear"]=0x02927, + ["Oacute"]=0x000D3, + ["oacute"]=0x000F3, + ["oast"]=0x0229B, + ["ocir"]=0x0229A, + ["Ocirc"]=0x000D4, + ["ocirc"]=0x000F4, + ["Ocy"]=0x0041E, + ["ocy"]=0x0043E, + ["odash"]=0x0229D, + ["Odblac"]=0x00150, + ["odblac"]=0x00151, + ["odiv"]=0x02A38, + ["odot"]=0x02299, + ["odsold"]=0x029BC, + ["OElig"]=0x00152, + ["oelig"]=0x00153, + ["ofcir"]=0x029BF, + ["Ofr"]=0x1D512, + ["ofr"]=0x1D52C, + ["ogon"]=0x002DB, + ["Ograve"]=0x000D2, + ["ograve"]=0x000F2, + ["ogt"]=0x029C1, + ["ohbar"]=0x029B5, + ["ohm"]=0x02126, + ["oint"]=0x0222E, + ["olarr"]=0x021BA, + ["olcir"]=0x029BE, + ["olcross"]=0x029BB, + ["olt"]=0x029C0, + ["Omacr"]=0x0014C, + ["omacr"]=0x0014D, + ["Omega"]=0x003A9, + ["omega"]=0x003C9, + ["omid"]=0x029B6, + ["ominus"]=0x02296, + ["Oopf"]=0x1D546, + ["oopf"]=0x1D560, + ["opar"]=0x029B7, + ["OpenCurlyDoubleQuote"]=0x0201C, + ["OpenCurlyQuote"]=0x02018, + ["operp"]=0x029B9, + ["oplus"]=0x02295, + ["Or"]=0x02A54, + ["or"]=0x02228, + ["orarr"]=0x021BB, + ["ord"]=0x02A5D, + ["order"]=0x02134, + ["orderof"]=0x02134, + ["ordf"]=0x000AA, + ["ordm"]=0x000BA, + ["origof"]=0x022B6, + ["oror"]=0x02A56, + ["orslope"]=0x02A57, + ["orv"]=0x02A5B, + ["oS"]=0x024C8, + ["Oscr"]=0x1D4AA, + ["oscr"]=0x02134, + ["Oslash"]=0x000D8, + ["oslash"]=0x000F8, + ["osol"]=0x02298, + ["Otilde"]=0x000D5, + ["otilde"]=0x000F5, + ["Otimes"]=0x02A37, + ["otimes"]=0x02297, + ["otimesas"]=0x02A36, + ["Ouml"]=0x000D6, + ["ouml"]=0x000F6, + ["ovbar"]=0x0233D, + ["OverBar"]=0x000AF, + ["OverBrace"]=0x0FE37, + ["OverBracket"]=0x023B4, + ["OverParenthesis"]=0x0FE35, + ["par"]=0x02225, + ["para"]=0x000B6, + ["parallel"]=0x02225, + ["parsim"]=0x02AF3, + ["parsl"]=0x02AFD, + ["part"]=0x02202, + ["PartialD"]=0x02202, + ["Pcy"]=0x0041F, + ["pcy"]=0x0043F, + ["percnt"]=0x00025, + ["period"]=0x0002E, + ["permil"]=0x02030, + ["perp"]=0x022A5, + ["pertenk"]=0x02031, + ["Pfr"]=0x1D513, + ["pfr"]=0x1D52D, + ["Phi"]=0x003A6, + ["phi"]=0x003D5, + ["phiv"]=0x003C6, + ["phmmat"]=0x02133, + ["phone"]=0x0260E, + ["Pi"]=0x003A0, + ["pi"]=0x003C0, + ["pitchfork"]=0x022D4, + ["piv"]=0x003D6, + ["planck"]=0x0210F, + ["planckh"]=0x0210E, + ["plankv"]=0x0210F, + ["plus"]=0x0002B, + ["plusacir"]=0x02A23, + ["plusb"]=0x0229E, + ["pluscir"]=0x02A22, + ["plusdo"]=0x02214, + ["plusdu"]=0x02A25, + ["pluse"]=0x02A72, + ["PlusMinus"]=0x000B1, + ["plusmn"]=0x000B1, + ["plussim"]=0x02A26, + ["plustwo"]=0x02A27, + ["pm"]=0x000B1, + ["Poincareplane"]=0x0210C, + ["pointint"]=0x02A15, + ["Popf"]=0x02119, + ["popf"]=0x1D561, + ["pound"]=0x000A3, + ["Pr"]=0x02ABB, + ["pr"]=0x0227A, + ["prap"]=0x02AB7, + ["prcue"]=0x0227C, + ["prE"]=0x02AB3, + ["pre"]=0x02AAF, + ["prec"]=0x0227A, + ["precapprox"]=0x02AB7, + ["preccurlyeq"]=0x0227C, + ["Precedes"]=0x0227A, + ["PrecedesEqual"]=0x02AAF, + ["PrecedesSlantEqual"]=0x0227C, + ["PrecedesTilde"]=0x0227E, + ["preceq"]=0x02AAF, + ["precnapprox"]=0x02AB9, + ["precneqq"]=0x02AB5, + ["precnsim"]=0x022E8, + ["precsim"]=0x0227E, + ["Prime"]=0x02033, + ["prime"]=0x02032, + ["primes"]=0x02119, + ["prnap"]=0x02AB9, + ["prnE"]=0x02AB5, + ["prnsim"]=0x022E8, + ["prod"]=0x0220F, + ["Product"]=0x0220F, + ["profalar"]=0x0232E, + ["profline"]=0x02312, + ["profsurf"]=0x02313, + ["prop"]=0x0221D, + ["Proportion"]=0x02237, + ["Proportional"]=0x0221D, + ["propto"]=0x0221D, + ["prsim"]=0x0227E, + ["prurel"]=0x022B0, + ["Pscr"]=0x1D4AB, + ["pscr"]=0x1D4C5, + ["Psi"]=0x003A8, + ["psi"]=0x003C8, + ["puncsp"]=0x02008, + ["Qfr"]=0x1D514, + ["qfr"]=0x1D52E, + ["qint"]=0x02A0C, + ["Qopf"]=0x0211A, + ["qopf"]=0x1D562, + ["qprime"]=0x02057, + ["Qscr"]=0x1D4AC, + ["qscr"]=0x1D4C6, + ["quaternions"]=0x0210D, + ["quatint"]=0x02A16, + ["quest"]=0x0003F, + ["questeq"]=0x0225F, + ["quot"]=0x00022, + ["rAarr"]=0x021DB, + ["race"]=0x029DA, + ["Racute"]=0x00154, + ["racute"]=0x00155, + ["radic"]=0x0221A, + ["raemptyv"]=0x029B3, + ["Rang"]=0x0300B, + ["rang"]=0x0232A, + ["rangd"]=0x02992, + ["range"]=0x029A5, + ["rangle"]=0x0232A, + ["raquo"]=0x000BB, + ["Rarr"]=0x021A0, + ["rArr"]=0x021D2, + ["rarr"]=0x02192, + ["rarrap"]=0x02975, + ["rarrb"]=0x021E5, + ["rarrbfs"]=0x02920, + ["rarrc"]=0x02933, + ["rarrfs"]=0x0291E, + ["rarrhk"]=0x021AA, + ["rarrlp"]=0x021AC, + ["rarrpl"]=0x02945, + ["rarrsim"]=0x02974, + ["Rarrtl"]=0x02916, + ["rarrtl"]=0x021A3, + ["rarrw"]=0x0219D, + ["rAtail"]=0x0291C, + ["ratail"]=0x0291A, + ["ratio"]=0x02236, + ["rationals"]=0x0211A, + ["RBarr"]=0x02910, + ["rBarr"]=0x0290F, + ["rbarr"]=0x0290D, + ["rbbrk"]=0x03015, + ["rbrace"]=0x0007D, + ["rbrack"]=0x0005D, + ["rbrke"]=0x0298C, + ["rbrksld"]=0x0298E, + ["rbrkslu"]=0x02990, + ["Rcaron"]=0x00158, + ["rcaron"]=0x00159, + ["Rcedil"]=0x00156, + ["rcedil"]=0x00157, + ["rceil"]=0x02309, + ["rcub"]=0x0007D, + ["Rcy"]=0x00420, + ["rcy"]=0x00440, + ["rdca"]=0x02937, + ["rdldhar"]=0x02969, + ["rdquo"]=0x0201D, + ["rdquor"]=0x0201D, + ["rdsh"]=0x021B3, + ["Re"]=0x0211C, + ["real"]=0x0211C, + ["realine"]=0x0211B, + ["realpart"]=0x0211C, + ["reals"]=0x0211D, + ["rect"]=0x025AD, + ["reg"]=0x000AE, + ["ReverseElement"]=0x0220B, + ["ReverseEquilibrium"]=0x021CB, + ["ReverseUpEquilibrium"]=0x0296F, + ["rfisht"]=0x0297D, + ["rfloor"]=0x0230B, + ["Rfr"]=0x0211C, + ["rfr"]=0x1D52F, + ["rHar"]=0x02964, + ["rhard"]=0x021C1, + ["rharu"]=0x021C0, + ["rharul"]=0x0296C, + ["rho"]=0x003C1, + ["rhov"]=0x003F1, + ["RightAngleBracket"]=0x0232A, + ["RightArrow"]=0x02192, + ["Rightarrow"]=0x021D2, + ["rightarrow"]=0x02192, + ["RightArrowBar"]=0x021E5, + ["RightArrowLeftArrow"]=0x021C4, + ["rightarrowtail"]=0x021A3, + ["RightCeiling"]=0x02309, + ["RightDoubleBracket"]=0x0301B, + ["RightDownTeeVector"]=0x0295D, + ["RightDownVector"]=0x021C2, + ["RightDownVectorBar"]=0x02955, + ["RightFloor"]=0x0230B, + ["rightharpoondown"]=0x021C1, + ["rightharpoonup"]=0x021C0, + ["rightleftarrows"]=0x021C4, + ["rightleftharpoons"]=0x021CC, + ["rightrightarrows"]=0x021C9, + ["rightsquigarrow"]=0x0219D, + ["RightTee"]=0x022A2, + ["RightTeeArrow"]=0x021A6, + ["RightTeeVector"]=0x0295B, + ["rightthreetimes"]=0x022CC, + ["RightTriangle"]=0x022B3, + ["RightTriangleBar"]=0x029D0, + ["RightTriangleEqual"]=0x022B5, + ["RightUpDownVector"]=0x0294F, + ["RightUpTeeVector"]=0x0295C, + ["RightUpVector"]=0x021BE, + ["RightUpVectorBar"]=0x02954, + ["RightVector"]=0x021C0, + ["RightVectorBar"]=0x02953, + ["ring"]=0x002DA, + ["risingdotseq"]=0x02253, + ["rlarr"]=0x021C4, + ["rlhar"]=0x021CC, + ["rmoust"]=0x023B1, + ["rmoustache"]=0x023B1, + ["rnmid"]=0x02AEE, + ["roang"]=0x03019, + ["roarr"]=0x021FE, + ["robrk"]=0x0301B, + ["ropar"]=0x02986, + ["Ropf"]=0x0211D, + ["ropf"]=0x1D563, + ["roplus"]=0x02A2E, + ["rotimes"]=0x02A35, + ["RoundImplies"]=0x02970, + ["rpar"]=0x00029, + ["rpargt"]=0x02994, + ["rppolint"]=0x02A12, + ["rrarr"]=0x021C9, + ["Rrightarrow"]=0x021DB, + ["Rscr"]=0x0211B, + ["rscr"]=0x1D4C7, + ["Rsh"]=0x021B1, + ["rsh"]=0x021B1, + ["rsqb"]=0x0005D, + ["rsquo"]=0x02019, + ["rsquor"]=0x02019, + ["rthree"]=0x022CC, + ["rtimes"]=0x022CA, + ["rtri"]=0x025B9, + ["rtrie"]=0x022B5, + ["rtrif"]=0x025B8, + ["rtriltri"]=0x029CE, + ["RuleDelayed"]=0x029F4, + ["ruluhar"]=0x02968, + ["rx"]=0x0211E, + ["Sacute"]=0x0015A, + ["sacute"]=0x0015B, + ["Sc"]=0x02ABC, + ["sc"]=0x0227B, + ["scap"]=0x02AB8, + ["Scaron"]=0x00160, + ["scaron"]=0x00161, + ["sccue"]=0x0227D, + ["scE"]=0x02AB4, + ["sce"]=0x02AB0, + ["Scedil"]=0x0015E, + ["scedil"]=0x0015F, + ["Scirc"]=0x0015C, + ["scirc"]=0x0015D, + ["scnap"]=0x02ABA, + ["scnE"]=0x02AB6, + ["scnsim"]=0x022E9, + ["scpolint"]=0x02A13, + ["scsim"]=0x0227F, + ["Scy"]=0x00421, + ["scy"]=0x00441, + ["sdot"]=0x022C5, + ["sdotb"]=0x022A1, + ["sdote"]=0x02A66, + ["searhk"]=0x02925, + ["seArr"]=0x021D8, + ["searr"]=0x02198, + ["searrow"]=0x02198, + ["sect"]=0x000A7, + ["semi"]=0x0003B, + ["seswar"]=0x02929, + ["setminus"]=0x02216, + ["setmn"]=0x02216, + ["sext"]=0x02736, + ["Sfr"]=0x1D516, + ["sfr"]=0x1D530, + ["sfrown"]=0x02322, + ["sharp"]=0x0266F, + ["SHCHcy"]=0x00429, + ["shchcy"]=0x00449, + ["SHcy"]=0x00428, + ["shcy"]=0x00448, + ["ShortDownArrow"]=0x02193, + ["ShortLeftArrow"]=0x02190, + ["shortmid"]=0x02223, + ["shortparallel"]=0x02225, + ["ShortRightArrow"]=0x02192, + ["ShortUpArrow"]=0x02191, + ["shy"]=0x000AD, + ["Sigma"]=0x003A3, + ["sigma"]=0x003C3, + ["sigmav"]=0x003C2, + ["sim"]=0x0223C, + ["simdot"]=0x02A6A, + ["sime"]=0x02243, + ["simeq"]=0x02243, + ["simg"]=0x02A9E, + ["simgE"]=0x02AA0, + ["siml"]=0x02A9D, + ["simlE"]=0x02A9F, + ["simne"]=0x02246, + ["simplus"]=0x02A24, + ["simrarr"]=0x02972, + ["slarr"]=0x02190, + ["SmallCircle"]=0x02218, + ["smallsetminus"]=0x02216, + ["smashp"]=0x02A33, + ["smeparsl"]=0x029E4, + ["smid"]=0x02223, + ["smile"]=0x02323, + ["smt"]=0x02AAA, + ["smte"]=0x02AAC, + ["smtes"]=0x02AAC, + ["SOFTcy"]=0x0042C, + ["softcy"]=0x0044C, + ["sol"]=0x0002F, + ["solb"]=0x029C4, + ["solbar"]=0x0233F, + ["Sopf"]=0x1D54A, + ["sopf"]=0x1D564, + ["spades"]=0x02660, + ["spadesuit"]=0x02660, + ["spar"]=0x02225, + ["sqcap"]=0x02293, + ["sqcaps"]=0x02293, + ["sqcup"]=0x02294, + ["sqcups"]=0x02294, + ["Sqrt"]=0x0221A, + ["sqsub"]=0x0228F, + ["sqsube"]=0x02291, + ["sqsubset"]=0x0228F, + ["sqsubseteq"]=0x02291, + ["sqsup"]=0x02290, + ["sqsupe"]=0x02292, + ["sqsupset"]=0x02290, + ["sqsupseteq"]=0x02292, + ["squ"]=0x025A1, + ["Square"]=0x025A1, + ["square"]=0x025A1, + ["SquareIntersection"]=0x02293, + ["SquareSubset"]=0x0228F, + ["SquareSubsetEqual"]=0x02291, + ["SquareSuperset"]=0x02290, + ["SquareSupersetEqual"]=0x02292, + ["SquareUnion"]=0x02294, + ["squarf"]=0x025AA, + ["squf"]=0x025AA, + ["srarr"]=0x02192, + ["Sscr"]=0x1D4AE, + ["sscr"]=0x1D4C8, + ["ssetmn"]=0x02216, + ["ssmile"]=0x02323, + ["sstarf"]=0x022C6, + ["Star"]=0x022C6, + ["star"]=0x02606, + ["starf"]=0x02605, + ["straightepsilon"]=0x003F5, + ["straightphi"]=0x003D5, + ["strns"]=0x000AF, + ["Sub"]=0x022D0, + ["sub"]=0x02282, + ["subdot"]=0x02ABD, + ["subE"]=0x02AC5, + ["sube"]=0x02286, + ["subedot"]=0x02AC3, + ["submult"]=0x02AC1, + ["subnE"]=0x02ACB, + ["subne"]=0x0228A, + ["subplus"]=0x02ABF, + ["subrarr"]=0x02979, + ["Subset"]=0x022D0, + ["subset"]=0x02282, + ["subseteq"]=0x02286, + ["subseteqq"]=0x02AC5, + ["SubsetEqual"]=0x02286, + ["subsetneq"]=0x0228A, + ["subsetneqq"]=0x02ACB, + ["subsim"]=0x02AC7, + ["subsub"]=0x02AD5, + ["subsup"]=0x02AD3, + ["succ"]=0x0227B, + ["succapprox"]=0x02AB8, + ["succcurlyeq"]=0x0227D, + ["Succeeds"]=0x0227B, + ["SucceedsEqual"]=0x02AB0, + ["SucceedsSlantEqual"]=0x0227D, + ["SucceedsTilde"]=0x0227F, + ["succeq"]=0x02AB0, + ["succnapprox"]=0x02ABA, + ["succneqq"]=0x02AB6, + ["succnsim"]=0x022E9, + ["succsim"]=0x0227F, + ["SuchThat"]=0x0220B, + ["Sum"]=0x02211, + ["sum"]=0x02211, + ["sung"]=0x0266A, + ["Sup"]=0x022D1, + ["sup"]=0x02283, + ["sup1"]=0x000B9, + ["sup2"]=0x000B2, + ["sup3"]=0x000B3, + ["supdot"]=0x02ABE, + ["supdsub"]=0x02AD8, + ["supE"]=0x02AC6, + ["supe"]=0x02287, + ["supedot"]=0x02AC4, + ["Superset"]=0x02283, + ["SupersetEqual"]=0x02287, + ["suphsol"]=0x02283, + ["suphsub"]=0x02AD7, + ["suplarr"]=0x0297B, + ["supmult"]=0x02AC2, + ["supnE"]=0x02ACC, + ["supne"]=0x0228B, + ["supplus"]=0x02AC0, + ["Supset"]=0x022D1, + ["supset"]=0x02283, + ["supseteq"]=0x02287, + ["supseteqq"]=0x02AC6, + ["supsetneq"]=0x0228B, + ["supsetneqq"]=0x02ACC, + ["supsim"]=0x02AC8, + ["supsub"]=0x02AD4, + ["supsup"]=0x02AD6, + ["swarhk"]=0x02926, + ["swArr"]=0x021D9, + ["swarr"]=0x02199, + ["swarrow"]=0x02199, + ["swnwar"]=0x0292A, + ["szlig"]=0x000DF, + ["Tab"]=0x00009, + ["target"]=0x02316, + ["tau"]=0x003C4, + ["tbrk"]=0x023B4, + ["Tcaron"]=0x00164, + ["tcaron"]=0x00165, + ["Tcedil"]=0x00162, + ["tcedil"]=0x00163, + ["Tcy"]=0x00422, + ["tcy"]=0x00442, + ["tdot"]=0x020DB, + ["telrec"]=0x02315, + ["Tfr"]=0x1D517, + ["tfr"]=0x1D531, + ["there4"]=0x02234, + ["Therefore"]=0x02234, + ["therefore"]=0x02234, + ["Theta"]=0x00398, + ["theta"]=0x003B8, + ["thetav"]=0x003D1, + ["thickapprox"]=0x02248, + ["thicksim"]=0x0223C, + ["ThickSpace"]=0x02009, + ["thinsp"]=0x02009, + ["ThinSpace"]=0x02009, + ["thkap"]=0x02248, + ["thksim"]=0x0223C, + ["THORN"]=0x000DE, + ["thorn"]=0x000FE, + ["Tilde"]=0x0223C, + ["tilde"]=0x002DC, + ["TildeEqual"]=0x02243, + ["TildeFullEqual"]=0x02245, + ["TildeTilde"]=0x02248, + ["times"]=0x000D7, + ["timesb"]=0x022A0, + ["timesbar"]=0x02A31, + ["timesd"]=0x02A30, + ["tint"]=0x0222D, + ["toea"]=0x02928, + ["top"]=0x022A4, + ["topbot"]=0x02336, + ["topcir"]=0x02AF1, + ["Topf"]=0x1D54B, + ["topf"]=0x1D565, + ["topfork"]=0x02ADA, + ["tosa"]=0x02929, + ["tprime"]=0x02034, + ["trade"]=0x02122, + ["triangle"]=0x025B5, + ["triangledown"]=0x025BF, + ["triangleleft"]=0x025C3, + ["trianglelefteq"]=0x022B4, + ["triangleq"]=0x0225C, + ["triangleright"]=0x025B9, + ["trianglerighteq"]=0x022B5, + ["tridot"]=0x025EC, + ["trie"]=0x0225C, + ["triminus"]=0x02A3A, + ["TripleDot"]=0x020DB, + ["triplus"]=0x02A39, + ["trisb"]=0x029CD, + ["tritime"]=0x02A3B, + ["trpezium"]=0x0FFFD, + ["Tscr"]=0x1D4AF, + ["tscr"]=0x1D4C9, + ["TScy"]=0x00426, + ["tscy"]=0x00446, + ["TSHcy"]=0x0040B, + ["tshcy"]=0x0045B, + ["Tstrok"]=0x00166, + ["tstrok"]=0x00167, + ["twixt"]=0x0226C, + ["twoheadleftarrow"]=0x0219E, + ["twoheadrightarrow"]=0x021A0, + ["Uacute"]=0x000DA, + ["uacute"]=0x000FA, + ["Uarr"]=0x0219F, + ["uArr"]=0x021D1, + ["uarr"]=0x02191, + ["Uarrocir"]=0x02949, + ["Ubrcy"]=0x0040E, + ["ubrcy"]=0x0045E, + ["Ubreve"]=0x0016C, + ["ubreve"]=0x0016D, + ["Ucirc"]=0x000DB, + ["ucirc"]=0x000FB, + ["Ucy"]=0x00423, + ["ucy"]=0x00443, + ["udarr"]=0x021C5, + ["Udblac"]=0x00170, + ["udblac"]=0x00171, + ["udhar"]=0x0296E, + ["ufisht"]=0x0297E, + ["Ufr"]=0x1D518, + ["ufr"]=0x1D532, + ["Ugrave"]=0x000D9, + ["ugrave"]=0x000F9, + ["uHar"]=0x02963, + ["uharl"]=0x021BF, + ["uharr"]=0x021BE, + ["uhblk"]=0x02580, + ["ulcorn"]=0x0231C, + ["ulcorner"]=0x0231C, + ["ulcrop"]=0x0230F, + ["ultri"]=0x025F8, + ["Umacr"]=0x0016A, + ["umacr"]=0x0016B, + ["uml"]=0x000A8, + ["UnderBar"]=0x00332, + ["UnderBrace"]=0x0FE38, + ["UnderBracket"]=0x023B5, + ["UnderParenthesis"]=0x0FE36, + ["Union"]=0x022C3, + ["UnionPlus"]=0x0228E, + ["Uogon"]=0x00172, + ["uogon"]=0x00173, + ["Uopf"]=0x1D54C, + ["uopf"]=0x1D566, + ["UpArrow"]=0x02191, + ["Uparrow"]=0x021D1, + ["uparrow"]=0x02191, + ["UpArrowBar"]=0x02912, + ["UpArrowDownArrow"]=0x021C5, + ["UpDownArrow"]=0x02195, + ["Updownarrow"]=0x021D5, + ["updownarrow"]=0x02195, + ["UpEquilibrium"]=0x0296E, + ["upharpoonleft"]=0x021BF, + ["upharpoonright"]=0x021BE, + ["uplus"]=0x0228E, + ["UpperLeftArrow"]=0x02196, + ["UpperRightArrow"]=0x02197, + ["Upsi"]=0x003D2, + ["upsi"]=0x003C5, + ["Upsilon"]=0x003A5, + ["upsilon"]=0x003C5, + ["UpTee"]=0x022A5, + ["UpTeeArrow"]=0x021A5, + ["upuparrows"]=0x021C8, + ["urcorn"]=0x0231D, + ["urcorner"]=0x0231D, + ["urcrop"]=0x0230E, + ["Uring"]=0x0016E, + ["uring"]=0x0016F, + ["urtri"]=0x025F9, + ["Uscr"]=0x1D4B0, + ["uscr"]=0x1D4CA, + ["utdot"]=0x022F0, + ["Utilde"]=0x00168, + ["utilde"]=0x00169, + ["utri"]=0x025B5, + ["utrif"]=0x025B4, + ["uuarr"]=0x021C8, + ["Uuml"]=0x000DC, + ["uuml"]=0x000FC, + ["uwangle"]=0x029A7, + ["vangrt"]=0x0299C, + ["varepsilon"]=0x003B5, + ["varkappa"]=0x003F0, + ["varnothing"]=0x02205, + ["varphi"]=0x003C6, + ["varpi"]=0x003D6, + ["varpropto"]=0x0221D, + ["vArr"]=0x021D5, + ["varr"]=0x02195, + ["varrho"]=0x003F1, + ["varsigma"]=0x003C2, + ["varsubsetneq"]=0x0228A, + ["varsubsetneqq"]=0x02ACB, + ["varsupsetneq"]=0x0228B, + ["varsupsetneqq"]=0x02ACC, + ["vartheta"]=0x003D1, + ["vartriangleleft"]=0x022B2, + ["vartriangleright"]=0x022B3, + ["Vbar"]=0x02AEB, + ["vBar"]=0x02AE8, + ["vBarv"]=0x02AE9, + ["Vcy"]=0x00412, + ["vcy"]=0x00432, + ["VDash"]=0x022AB, + ["Vdash"]=0x022A9, + ["vDash"]=0x022A8, + ["vdash"]=0x022A2, + ["Vdashl"]=0x02AE6, + ["Vee"]=0x022C1, + ["vee"]=0x02228, + ["veebar"]=0x022BB, + ["veeeq"]=0x0225A, + ["vellip"]=0x022EE, + ["Verbar"]=0x02016, + ["verbar"]=0x0007C, + ["Vert"]=0x02016, + ["vert"]=0x0007C, + ["VerticalBar"]=0x02223, + ["VerticalLine"]=0x0007C, + ["VerticalSeparator"]=0x02758, + ["VerticalTilde"]=0x02240, + ["VeryThinSpace"]=0x0200A, + ["Vfr"]=0x1D519, + ["vfr"]=0x1D533, + ["vltri"]=0x022B2, + ["vnsub"]=0x02282, + ["vnsup"]=0x02283, + ["Vopf"]=0x1D54D, + ["vopf"]=0x1D567, + ["vprop"]=0x0221D, + ["vrtri"]=0x022B3, + ["Vscr"]=0x1D4B1, + ["vscr"]=0x1D4CB, + ["vsubnE"]=0x02ACB, + ["vsubne"]=0x0228A, + ["vsupnE"]=0x02ACC, + ["vsupne"]=0x0228B, + ["Vvdash"]=0x022AA, + ["vzigzag"]=0x0299A, + ["Wcirc"]=0x00174, + ["wcirc"]=0x00175, + ["wedbar"]=0x02A5F, + ["Wedge"]=0x022C0, + ["wedge"]=0x02227, + ["wedgeq"]=0x02259, + ["weierp"]=0x02118, + ["Wfr"]=0x1D51A, + ["wfr"]=0x1D534, + ["Wopf"]=0x1D54E, + ["wopf"]=0x1D568, + ["wp"]=0x02118, + ["wr"]=0x02240, + ["wreath"]=0x02240, + ["Wscr"]=0x1D4B2, + ["wscr"]=0x1D4CC, + ["xcap"]=0x022C2, + ["xcirc"]=0x025EF, + ["xcup"]=0x022C3, + ["xdtri"]=0x025BD, + ["Xfr"]=0x1D51B, + ["xfr"]=0x1D535, + ["xhArr"]=0x027FA, + ["xharr"]=0x027F7, + ["Xi"]=0x0039E, + ["xi"]=0x003BE, + ["xlArr"]=0x027F8, + ["xlarr"]=0x027F5, + ["xmap"]=0x027FC, + ["xnis"]=0x022FB, + ["xodot"]=0x02A00, + ["Xopf"]=0x1D54F, + ["xopf"]=0x1D569, + ["xoplus"]=0x02A01, + ["xotime"]=0x02A02, + ["xrArr"]=0x027F9, + ["xrarr"]=0x027F6, + ["Xscr"]=0x1D4B3, + ["xscr"]=0x1D4CD, + ["xsqcup"]=0x02A06, + ["xuplus"]=0x02A04, + ["xutri"]=0x025B3, + ["xvee"]=0x022C1, + ["xwedge"]=0x022C0, + ["Yacute"]=0x000DD, + ["yacute"]=0x000FD, + ["YAcy"]=0x0042F, + ["yacy"]=0x0044F, + ["Ycirc"]=0x00176, + ["ycirc"]=0x00177, + ["Ycy"]=0x0042B, + ["ycy"]=0x0044B, + ["yen"]=0x000A5, + ["Yfr"]=0x1D51C, + ["yfr"]=0x1D536, + ["YIcy"]=0x00407, + ["yicy"]=0x00457, + ["Yopf"]=0x1D550, + ["yopf"]=0x1D56A, + ["Yscr"]=0x1D4B4, + ["yscr"]=0x1D4CE, + ["YUcy"]=0x0042E, + ["yucy"]=0x0044E, + ["Yuml"]=0x00178, + ["yuml"]=0x000FF, + ["Zacute"]=0x00179, + ["zacute"]=0x0017A, + ["Zcaron"]=0x0017D, + ["zcaron"]=0x0017E, + ["Zcy"]=0x00417, + ["zcy"]=0x00437, + ["Zdot"]=0x0017B, + ["zdot"]=0x0017C, + ["zeetrf"]=0x02128, + ["ZeroWidthSpace"]=0x0200B, + ["zeta"]=0x003B6, + ["Zfr"]=0x02128, + ["zfr"]=0x1D537, + ["ZHcy"]=0x00416, + ["zhcy"]=0x00436, + ["zigrarr"]=0x021DD, + ["Zopf"]=0x02124, + ["zopf"]=0x1D56B, + ["Zscr"]=0x1D4B5, + ["zscr"]=0x1D4CF, +} diff --git a/tex/context/base/math-ini.lua b/tex/context/base/math-ini.lua index 1d11745a6..6b2752cff 100644 --- a/tex/context/base/math-ini.lua +++ b/tex/context/base/math-ini.lua @@ -6,7 +6,6 @@ if not modules then modules = { } end modules ['math-ini'] = { license = "see context related readme files" } - --[[ldx-- <p>Math definitions. This code may move.</p> --ldx]]-- @@ -87,13 +86,13 @@ function mathematics.radical(small_family,small_slot,large_family,large_slot) return ("\\radical%s=\"%02X%04X%\"02X%04X"):format(target,small_family,small_slot,large_family,large_slot) end function mathematics.mathchar(class,family,slot) - return ("\\omathchar\"%X%02X%04X"):format(class,family,slot) + return ("\\omathchar\"%X%02X%04X "):format(class,family,slot) end function mathematics.mathaccent(class,family,slot) - return ("\\omathaccent\"%X%02X%04X"):format(class,family,slot) + return ("\\omathaccent\"%X%02X%04X "):format(class,family,slot) end function mathematics.delimiter(class,family,slot,largefamily,largeslot) - return ("\\odelimiter\"%X%02X%04X\"%02X%04X"):format(class,family,slot,largefamily,largeslot) + return ("\\odelimiter\"%X%02X%04X\"%02X%04X "):format(class,family,slot,largefamily,largeslot) end function mathematics.mathchardef(name,class,family,slot) -- we can avoid this one return ("\\omathchardef\\%s\"%X%02X%04X"):format(name,class,family,slot) diff --git a/tex/context/base/math-ini.mkiv b/tex/context/base/math-ini.mkiv index 0b1b53caa..4d516a45c 100644 --- a/tex/context/base/math-ini.mkiv +++ b/tex/context/base/math-ini.mkiv @@ -19,6 +19,7 @@ % test $[[\char948 \ctxlua{tex.sprint(utf.char(948))}]]$ \registerctxluafile{math-ini}{1.001} +\registerctxluafile{math-ent}{1.001} % \registerctxluafile{math-def}{1.001} % \ctxlua{mathematics.traditional()} diff --git a/tex/context/base/math-ini.tex b/tex/context/base/math-ini.tex index 4fc87a676..7ffef6bb8 100644 --- a/tex/context/base/math-ini.tex +++ b/tex/context/base/math-ini.tex @@ -35,7 +35,7 @@ \def\@@mathlimopcomm#1{\mathop{#1}} %no \limits \def\@@mathnolopcomm#1{\mathop{#1}\nolimits} -\def\@@mathboxcomm #1{\leavevmode\hbox{$\m@th#1$}} +\def\@@mathboxcomm #1{\dontleavehmode\hbox{$\m@th#1$}} \chardef\mathordcode = 0 \let\mathordcomm \mathord \chardef\mathopcode = 1 \let\mathopcomm \mathop @@ -602,7 +602,10 @@ %D needed for sin, cos etc -\def\mfunction#1{{\mr#1}} +\def\mfunction #1{{\mr#1}} + +% \def\mlimitsfunction #1{\mathlimopcomm{{\mr#1}} +% \def\mnolimitsfunction#1{\mathnolopcomm{{\mr#1}} %D Taco posted this solution as response to a mail by Olivier, so %D let's integrate it here. diff --git a/tex/context/base/node-ini.lua b/tex/context/base/node-ini.lua index 76cbe3b76..5923a49e4 100644 --- a/tex/context/base/node-ini.lua +++ b/tex/context/base/node-ini.lua @@ -336,7 +336,9 @@ do local starttiming, stoptiming = input.starttiming, input.stoptiming function nodes.process_characters(head) - if status.output_active then -- not ok, we need a generic blocker, pagebody ! / attr tex.attibutes + -- not ok yet; we need a generic blocker + -- if status.output_active then + if false then -- status.output_active then return head, false -- true else -- either next or not, but definitely no already processed list diff --git a/tex/context/base/syst-cat.mkiv b/tex/context/base/syst-cat.mkiv index 212d372c1..46ee0f394 100644 --- a/tex/context/base/syst-cat.mkiv +++ b/tex/context/base/syst-cat.mkiv @@ -23,6 +23,7 @@ \ifx\nilcatcodes \undefined \newcatcodetable \nilcatcodes \fi \ifx\texcatcodes \undefined \newcatcodetable \texcatcodes \fi \ifx\ctxcatcodes \undefined \newcatcodetable \ctxcatcodes \fi +\ifx\notcatcodes \undefined \newcatcodetable \notcatcodes \fi \ifx\mthcatcodes \undefined \newcatcodetable \mthcatcodes \fi % brrr \ifx\vrbcatcodes \undefined \newcatcodetable \vrbcatcodes \fi \ifx\prtcatcodes \undefined \newcatcodetable \prtcatcodes \fi @@ -106,6 +107,7 @@ tex.nilcatcodes = \number\nilcatcodes ; tex.texcatcodes = \number\texcatcodes ; tex.ctxcatcodes = \number\ctxcatcodes ; + tex.notcatcodes = \number\notcatcodes ; tex.mthcatcodes = \number\mthcatcodes ; tex.vrbcatcodes = \number\vrbcatcodes ; tex.prtcatcodes = \number\prtcatcodes ; diff --git a/tex/context/base/syst-cat.tex b/tex/context/base/syst-cat.tex index d5424342c..8994f207b 100644 --- a/tex/context/base/syst-cat.tex +++ b/tex/context/base/syst-cat.tex @@ -452,14 +452,26 @@ \chardef\activehackcode=`~ -\def\defineactivecharacter #1 #2% +% \def\defineactivecharacter #1 #2% +% {\cctcounterc\uccode\activehackcode +% \uccode\activehackcode\expandafter\doifnumberelse\expandafter{\string#1}\empty`#1% +% \catcode\uccode\activehackcode13 +% \uppercase{\def\next{~}}% +% \uccode\activehackcode\cctcounterc +% \expandafter\expandafter\expandafter\def\expandafter\next\expandafter +% {\expandafter\dohandleactivecharacter\next{#2}}} +% +% \defineactivecharacter "0EFFF {oeps} \utfchar{0xEFFF} + +\def\defineactivecharacter #1#2 #3% {\cctcounterc\uccode\activehackcode - \uccode\activehackcode\expandafter\doifnumberelse\expandafter{\string#1}\empty`#1% + \if#1"\uccode\activehackcode\expandafter\doifnumberelse\expandafter{\string#1#2}\empty #1#2\else + \uccode\activehackcode\expandafter\doifnumberelse\expandafter{\string#1#2}\empty`#1#2\fi \catcode\uccode\activehackcode13 \uppercase{\def\next{~}}% \uccode\activehackcode\cctcounterc \expandafter\expandafter\expandafter\def\expandafter\next\expandafter - {\expandafter\dohandleactivecharacter\next{#2}}} + {\expandafter\dohandleactivecharacter\next{#3}}} \chardef\activecharactermode\plusone % overloading still backward compatible diff --git a/tex/context/base/x-mathml.lua b/tex/context/base/x-mathml.lua new file mode 100644 index 000000000..fa5e617e6 --- /dev/null +++ b/tex/context/base/x-mathml.lua @@ -0,0 +1,300 @@ +if not modules then modules = { } end modules ['x-mathml'] = { + version = 1.001, + comment = "companion to x-mathml.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +lxml.mml = lxml.mml or { } + +local texsprint = tex.sprint +local format = string.format +local xmlsprint = xml.sprint +local xmlcprint = xml.cprint + +-- an alternative is to remap to private codes, where we can have +-- different properties .. to be done; this will move and become +-- generic + +local n_replacements = { +-- [" "] = utf.char(0x2002), -- "&textspace;" -> tricky, no &; in mkiv + ["."] = "{.}", + [","] = "{,}", + [" "] = "", +} + +local o_replacements = { + ["@l"] = "\\mmlleftdelimiter.", + ["@r"] = "\\mmlrightdelimiter.", + ["{"] = "\\mmlleftdelimiter\\lbrace", + ["}"] = "\\mmlrightdelimiter\\rbrace", + ["("] = "\\mmlleftdelimiter(", + [")"] = "\\mmlrightdelimiter)", + ["["] = "\\mmlleftdelimiter[", + ["]"] = "\\mmlrightdelimiter]", + ["<"] = "\\mmlleftdelimiter<", + [">"] = "\\mmlrightdelimiter>", + ["#"] = "\\mmlchar{35}", + ["$"] = "\\mmlchar{36}", -- $ + ["%"] = "\\mmlchar{37}", + ["&"] = "\\mmlchar{38}", + ["^"] = "\\mmlchar{94}{}", -- strange, sometimes luatex math sees the char instead of \char + ["_"] = "\\mmlchar{95}{}", -- so we need the {} + ["~"] = "\\mmlchar{126}", + [" "] = "", +} + +local i_replacements = { + ["sin"] = "\\mathopnolimits{sin}", + ["cos"] = "\\mathopnolimits{cos}", + ["abs"] = "\\mathopnolimits{abs}", + ["arg"] = "\\mathopnolimits{arg}", + ["codomain"] = "\\mathopnolimits{codomain}", + ["curl"] = "\\mathopnolimits{curl}", + ["determinant"] = "\\mathopnolimits{det}", + ["divergence"] = "\\mathopnolimits{div}", + ["domain"] = "\\mathopnolimits{domain}", + ["gcd"] = "\\mathopnolimits{gcd}", + ["grad"] = "\\mathopnolimits{grad}", + ["identity"] = "\\mathopnolimits{id}", + ["image"] = "\\mathopnolimits{image}", + ["lcm"] = "\\mathopnolimits{lcm}", + ["max"] = "\\mathopnolimits{max}", + ["median"] = "\\mathopnolimits{median}", + ["min"] = "\\mathopnolimits{min}", + ["mode"] = "\\mathopnolimits{mode}", + ["mod"] = "\\mathopnolimits{mod}", + ["polar"] = "\\mathopnolimits{Polar}", + ["exp"] = "\\mathopnolimits{exp}", + ["ln"] = "\\mathopnolimits{ln}", + ["log"] = "\\mathopnolimits{log}", + ["sin"] = "\\mathopnolimits{sin}", + ["arcsin"] = "\\mathopnolimits{arcsin}", + ["sinh"] = "\\mathopnolimits{sinh}", + ["arcsinh"] = "\\mathopnolimits{arcsinh}", + ["cos"] = "\\mathopnolimits{cos}", + ["arccos"] = "\\mathopnolimits{arccos}", + ["cosh"] = "\\mathopnolimits{cosh}", + ["arccosh"] = "\\mathopnolimits{arccosh}", + ["tan"] = "\\mathopnolimits{tan}", + ["arctan"] = "\\mathopnolimits{arctan}", + ["tanh"] = "\\mathopnolimits{tanh}", + ["arctanh"] = "\\mathopnolimits{arctanh}", + ["cot"] = "\\mathopnolimits{cot}", + ["arccot"] = "\\mathopnolimits{arccot}", + ["coth"] = "\\mathopnolimits{coth}", + ["arccoth"] = "\\mathopnolimits{arccoth}", + ["csc"] = "\\mathopnolimits{csc}", + ["arccsc"] = "\\mathopnolimits{arccsc}", + ["csch"] = "\\mathopnolimits{csch}", + ["arccsch"] = "\\mathopnolimits{arccsch}", + ["sec"] = "\\mathopnolimits{sec}", + ["arcsec"] = "\\mathopnolimits{arcsec}", + ["sech"] = "\\mathopnolimits{sech}", + ["arcsech"] = "\\mathopnolimits{arcsech}", + [" "] = "", + + ["false"] = "{\\mr false}", + ["notanumber"] = "{\\mr NaN}", + ["otherwise"] = "{\\mr otherwise}", + ["true"] = "{\\mr true}", + ["declare"] = "{\\mr declare}", + ["as"] = "{\\mr as}", +} + +function lxml.mml.checked_operator(str) + texsprint(tex.ctxcatcodes,(str:gsub(".",o_replacements))) +end + +function lxml.mml.mn(id,pattern) + local str = xml.content(lxml.id(id),pattern) or "" + texsprint(tex.ctxcatcodes,(str:gsub(".",n_replacements))) +end +function lxml.mml.mo(id,pattern) + local str = xml.content(lxml.id(id),pattern) or "" + tex.sprint(tex.ctxcatcodes,(str:gsub(".",o_replacements))) +end +function lxml.mml.mi(id,pattern) + local str = xml.content(lxml.id(id),pattern) or "" + str = str:gsub("^%s*(.*)%s*$","%1") + local rep = i_replacements[str] + if rep then + tex.sprint(tex.ctxcatcodes,rep) + else + tex.sprint(tex.ctxcatcodes,(str:gsub(".",i_replacements))) + end +end + +function lxml.mml.mfenced(id,pattern) -- multiple separators + id = lxml.id(id) + local left, right, separators = id.at.open or "(", id.at.close or ")", id.at.separators or "," + local l, r = left:find("[%(%{%<%[]"), right:find("[%)%}%>%]]") + texsprint(tex.ctxcatcodes,"\\enabledelimiter") + if l then + texsprint(tex.ctxcatcodes,o_replacements[left]) + else + texsprint(tex.ctxcatcodes,o_replacements["@l"]) + texsprint(tex.ctxcatcodes,left) + end + texsprint(tex.ctxcatcodes,"\\disabledelimiter") + local n = xml.count(id,pattern) + if n == 0 then + -- skip + elseif n == 1 then + lxml.all(id,pattern) + else + local t = { } + for s in utf.gmatch(separators,"([^%s])") do + t[#t+1] = s + end + for i=1,n do + lxml.idx(id,pattern,i) -- kind of slow, some day ... + if i < n then + local m = t[i] or t[#t] or "" + if m == "|" then + m = "\\enabledelimiter\\middle|\\relax\\disabledelimiter" + elseif m == "{" then + m = "\\{" + elseif m == "}" then + m = "\\}" + end + texsprint(tex.ctxcatcodes,m) + end + end + end + texsprint(tex.ctxcatcodes,"\\enabledelimiter") + if r then + texsprint(tex.ctxcatcodes,o_replacements[right]) + else + texsprint(tex.ctxcatcodes,right) + texsprint(tex.ctxcatcodes,o_replacements["@r"]) + end + texsprint(tex.ctxcatcodes,"\\disabledelimiter") +end + +local function flush(e,tag,toggle) + -- texsprint(tex.ctxcatcodes,(toggle and "^{") or "_{") + if toggle then + texsprint(tex.ctxcatcodes,"^{") + else + texsprint(tex.ctxcatcodes,"_{") + end + if tag == "none" then + texsprint(tex.ctxcatcodes,"{}") + else + xmlsprint(e.dt) + end + if not toggle then + texsprint(tex.ctxcatcodes,"}") + else + texsprint(tex.ctxcatcodes,"}{}") + end + return not toggle +end + +function lxml.mml.mmultiscripts(id) + local done, toggle = false, false + id = lxml.id(id) + -- for i=1,#id.dt do local e = id.dt[i] if type(e) == table then ... + for r, d, k in xml.elements(id,"/*") do + local e = d[k] + local tag = e.tg + if tag == "mprescripts" then + texsprint(tex.ctxcatcodes,"{}") + done = true + elseif done then + toggle = flush(e,tag,toggle) + end + end + local done, toggle = false, false + for r, d, k in xml.elements(id,"/*") do + local e = d[k] + local tag = e.tg + if tag == "mprescripts" then + break + elseif done then + toggle = flush(e,tag,toggle) + else + xmlsprint(e.dt) + done = true + end + end +end + +local columnalignments = { + left = "flushleft", + right = "flushright", + center = "middle", +} + +local rowalignments = { + top = "high", + bottom = "low", + center = "lohi", + baseline = "top", + axis = "lohi", +} + +local frametypes = { + none = "off", + solid = "on", + dashed = "on", +} + +function lxml.mml.mtable(root) + + root = lxml.id(root) + + -- todo: align, rowspacing, columnspacing, rowlines, columnlines + + local at = root.at + local rowalign = at.rowalign + local columnalign = at.columnalign + local frame = at.frame + local rowaligns = rowalign and rowalign :split(" ") -- we have a faster one + local columnaligns = columnalign and columnalign:split(" ") -- we have a faster one + local frames = frame and frame :split(" ") -- we have a faster one + local framespacing = at.framespacing or ".5ex" + + texsprint(tex.ctxcatcodes, format("\\bTABLE[frame=%s,offset=%s]",frametypes[frame or "none"] or "off",framespacing)) + for r, d, k in xml.elements(root,"/(mml:mtr|mml:mlabeledtr)") do + texsprint(tex.ctxcatcodes,"\\bTR") + local dk = d[k] + local at = dk.at + local col = 0 + local rfr = at.frame or (frames and frames [#frames]) + local rra = at.rowalign or (rowaligns and rowaligns [#rowaligns]) + local rca = at.columnalign or (columnaligns and columnaligns[#columnaligns]) + for rr, dd, kk in xml.elements(dk,"/mml:mtd") do + col = col + 1 + local dk = dd[kk] + local at = dk.at + local rowspan, columnspan = at.rowspan or 1, at.columnspan or 1 + local cra = rowalignments [at.rowalign or (rowaligns and rowaligns [col]) or rra or "center"] or "lohi" + local cca = columnalignments[at.columnalign or (columnaligns and columnaligns[col]) or rca or "center"] or "middle" + local cfr = frametypes [at.frame or (frames and frames [col]) or rfr or "none" ] or "off" + texsprint(tex.ctxcatcodes,format("\\bTD[align={%s,%s},frame=%s,nx=%s,ny=%s]$\\ignorespaces",cra,cca,cfr,columnspan,rowspan)) + xmlcprint(dk) + texsprint(tex.ctxcatcodes,"\\removeunwantedspaces$\\eTD") -- $ + end + if dk.tg == "mlabeledtr" then + texsprint(tex.ctxcatcodes,"\\bTD") + xmlcprint(xml.first(dk,"/!mml:mtd")) + texsprint(tex.ctxcatcodes,"\\eTD") + end + texsprint(tex.ctxcatcodes,"\\eTR") + end + texsprint(tex.ctxcatcodes, "\\eTABLE") +end + +function lxml.mml.csymbol(root) + root = lxml.id(root) + local encoding = root.at.encoding or "" + local hash = url.hashed((root.at.definitionUrl or ""):lower()) + local full = hash.original or "" + local base = hash.path or "" + local text = string.strip(xml.content(root) or "") + texsprint(tex.ctxcatcodes,format("\\mmlapplycsymbol{%s}{%s}{%s}{%s}",full,base,encoding,text)) +end + diff --git a/tex/context/base/x-mmc.mkiv b/tex/context/base/x-mmc.mkiv index 981dab162..042ef3406 100644 --- a/tex/context/base/x-mmc.mkiv +++ b/tex/context/base/x-mmc.mkiv @@ -11,263 +11,63 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. +% todo: more consistent both pi's and attributes to apply + \doifnotmode {atpragma} {\endinput} % \xmlfilter{#1}{/*/name()} -> \xmltag -%D Remark: from now on this is a module and no longer an xtag -%D filter. There is an intermediate cleaner module but it has -%D some namespace limitations. Here we do it the \MKV\ way. +\xmlresolveentities \startluacode - do - - lxml.mml = lxml.mml or { } - - local texsprint = tex.sprint - local format = string.format - local xmlsprint = xml.sprint - local xmlcprint = xml.cprint - - -- an alternative is to remap to private codes, where we can have - -- different properties .. to be done - - local n_replacements = { - -- [" "] = utf.char(0x2002), -- "&textspace;" -> tricky, no &; in mkiv - ["."] = "{.}", - [","] = "{,}", - [" "] = "", - } - local o_replacements = { - ["{"] = "\\mmlleftdelimiter\\lbrace", - ["}"] = "\\mmlrightdelimiter\\rbrace", - ["("] = "\\mmlleftdelimiter(", - [")"] = "\\mmlrightdelimiter)", - ["["] = "\\mmlleftdelimiter[", - ["]"] = "\\mmlrightdelimiter]", - ["<"] = "\\mmlleftdelimiter<", - [">"] = "\\mmlrightdelimiter>", - ["#"] = "\\mmlchar{35}", - ["$"] = "\\mmlchar{36}", -- $ - ["%"] = "\\mmlchar{37}", - ["&"] = "\\mmlchar{38}", - ["^"] = "\\mmlchar{94}{}", -- strange, sometimes luatex math see the char instead of \char - ["_"] = "\\mmlchar{95}{}", -- so we need the {} - ["~"] = "\\mmlchar{126}", - [" "] = "", - } - local i_replacements = { - ["sin"] = "\\mmlnolim{sin}", - ["cos"] = "\\mmlnolim{cos}", - ["abs"] = "\\mmlnolim{abs}", - ["arg"] = "\\mmlnolim{arg}", - ["codomain"] = "\\mmlnolim{codomain}", - ["curl"] = "\\mmlnolim{curl}", - ["determinant"] = "\\mmlnolim{det}", - ["divergence"] = "\\mmlnolim{div}", - ["domain"] = "\\mmlnolim{domain}", - ["false"] = "\\mmlnolim{false}", - ["gcd"] = "\\mmlnolim{gcd}", - ["grad"] = "\\mmlnolim{grad}", - ["identity"] = "\\mmlnolim{id}", - ["image"] = "\\mmlnolim{image}", - ["lcm"] = "\\mmlnolim{lcm}", - ["max"] = "\\mmlnolim{max}", - ["median"] = "\\mmlnolim{median}", - ["min"] = "\\mmlnolim{min}", - ["mode"] = "\\mmlnolim{mode}", - ["mod"] = "\\mmlnolim{mod}", - ["notanumber"] = "\\mmlnolim{NaN}", - ["otherwise"] = "\\mmlnolim{otherwise}", - ["true"] = "\\mmlnolim{true}", - ["declare"] = "\\mmlnolim{declare}", - ["as"] = "\\mmlnolim{as}", - ["polar"] = "\\mmlnolim{Polar}", - ["exp"] = "\\mmlnolim{exp}", - ["ln"] = "\\mmlnolim{ln}", - ["log"] = "\\mmlnolim{log}", - ["sin"] = "\\mmlnolim{sin}", - ["arcsin"] = "\\mmlnolim{arcsin}", - ["sinh"] = "\\mmlnolim{sinh}", - ["arcsinh"] = "\\mmlnolim{arcsinh}", - ["cos"] = "\\mmlnolim{cos}", - ["arccos"] = "\\mmlnolim{arccos}", - ["cosh"] = "\\mmlnolim{cosh}", - ["arccosh"] = "\\mmlnolim{arccosh}", - ["tan"] = "\\mmlnolim{tan}", - ["arctan"] = "\\mmlnolim{arctan}", - ["tanh"] = "\\mmlnolim{tanh}", - ["arctanh"] = "\\mmlnolim{arctanh}", - ["cot"] = "\\mmlnolim{cot}", - ["arccot"] = "\\mmlnolim{arccot}", - ["coth"] = "\\mmlnolim{coth}", - ["arccoth"] = "\\mmlnolim{arccoth}", - ["csc"] = "\\mmlnolim{csc}", - ["arccsc"] = "\\mmlnolim{arccsc}", - ["csch"] = "\\mmlnolim{csch}", - ["arccsch"] = "\\mmlnolim{arccsch}", - ["sec"] = "\\mmlnolim{sec}", - ["arcsec"] = "\\mmlnolim{arcsec}", - ["sech"] = "\\mmlnolim{sech}", - ["arcsech"] = "\\mmlnolim{arcsech}", - [" "] = "", - } - - function lxml.mml.prepare_number(id,pattern) - local str = xml.content(lxml.id(id),pattern) or "" - texsprint(tex.ctxcatcodes,(str:gsub(".",n_replacements))) - end - function lxml.mml.prepare_operator(id,pattern) - local str = xml.content(lxml.id(id),pattern) or "" - tex.sprint(tex.ctxcatcodes,(str:gsub(".",o_replacements))) - end - function lxml.mml.prepare_identifier(id,pattern) - local str = xml.content(lxml.id(id),pattern) or "" - str = str:gsub("^%s*(.*)%s*$","%1") - local rep = i_replacements[str] - if rep then - tex.sprint(tex.ctxcatcodes,rep) - else - tex.sprint(tex.ctxcatcodes,(str:gsub(".",i_replacements))) - end - end - - function lxml.mml.connect(id,pattern,separators) -- multiple separators - local n = xml.count(id,pattern) - if n == 0 then - -- skip - elseif n == 1 then - lxml.all(id,pattern) - else - local t = { } - for s in utf.gmatch(separators,"([^%s])") do - t[#t+1] = s - end - for i=1,n do - if i > 1 then - texsprint(tex.ctxcatcodes,"{") - texsprint(t[i] or t[#t] or "") - texsprint(tex.ctxcatcodes,"}") - end - lxml.idx(id,pattern,i) -- kind of slow, some day ... - end - end - end - - local function flush(e,tag,toggle) - -- texsprint(tex.ctxcatcodes,(toggle and "^{") or "_{") - if toggle then - texsprint(tex.ctxcatcodes,"^{") - else - texsprint(tex.ctxcatcodes,"_{") - end - if tag == "none" then - texsprint(tex.ctxcatcodes,"{}") - else - xmlsprint(e.dt) - end - if not toggle then - texsprint(tex.ctxcatcodes,"}") - else - texsprint(tex.ctxcatcodes,"}{}") - end - return not toggle - end - - function lxml.mml.mmultiscripts(id) - local done, toggle = false, false - id = lxml.id(id) - -- for i=1,#id.dt do local e = id.dt[i] if type(e) == table then ... - for r, d, k in xml.elements(id,"/*") do - local e = d[k] - local tag = e.tg - if tag == "mprescripts" then - texsprint(tex.ctxcatcodes,"{}") - done = true - elseif done then - toggle = flush(e,tag,toggle) - end - end - local done, toggle = false, false - for r, d, k in xml.elements(id,"/*") do - local e = d[k] - local tag = e.tg - if tag == "mprescripts" then - break - elseif done then - toggle = flush(e,tag,toggle) - else - xmlsprint(e.dt) - done = true - end + function math.register_xml_entities() + local entities, char = xml.entities, utf.char + for name, unicode in pairs(math.entities) do + if not entities[name] then + entities[name] = char(unicode) end end + end + math.register_xml_entities() + + -- not yet needed, we have class info in char-def already + -- + -- characters.data[0x2190].activemath = "mathleftarrow" + -- characters.data[0x2190].activemath = "mathuparrow" + -- characters.data[0x2192].activemath = "mathrightarrow" + -- characters.data[0x2193].activemath = "mathdownarrow" + -- + -- function characters.activate(catcodes) + -- local char, sprint, format = utf.char, tex.sprint, string.format + -- for k,v in pairs(characters.data) do + -- local a = v.activemath + -- if a then -- how fast is this? + -- sprint(format("\\letcatcodecommand %s %s \\%s",catcodes,k,a)) + -- end + -- end + -- end + -- + -- better do this the official way, i.e. defineactivecharacter since it + -- permits different meanings for different catcode tables (todo) + -- + -- characters.activate(tex.ctxcatcodes) + -- characters.activate(tex.notcatcodes) +\stopluacode - local columnalignments = { - left = "flushleft", - right = "flushright", - center = "middle", - } - - local rowalignments = { - top = "high", - bottom = "low", - center = "lohi", - baseline = "top", - axis = "lohi", - } +% \def\mathrightarrow{\normalorfiller\rightarrow\rightarrowfill} +% \def\mathleftarrow {\normalorfiller\leftarrow \leftarrowfill} +% \def\mathdownarrow {\mathortext \downarrow \empty} +% \def\mathuparrow {\mathortext \uparrow \empty} - local frames = { - none = "off", - solid = "on", - dashed = "on", - } +% \def\mathunderbrace{\normalorfiller\empty\upbracefill} +% \def\mathoverbrace {\normalorfiller\empty\downbracefill} +% \def\mathunderbar {\normalorfiller\hrule\hrulefill} +% \def\mathoverbar {\normalorfiller\hrule\hrulefill} +% \def\mathhat {\normalorfiller\empty\empty} % todo - function lxml.mml.mtable(root) - - root = lxml.id(root) - - local at = root.at - local rowalign = at.rowalign - local columnalign = at.columnalign - local rowaligns = rowalign and rowalign :split(",") -- we have a faster one - local columnaligns = columnalign and columnalign:split(",") -- we have a faster one - - -- todo: align, rowspacing, columnspacing, rowlines, columnlines - - local frame = frames[at.frame or "none"] - local framespacing = at.framespacing or ".5ex" - - texsprint(tex.ctxcatcodes, format("\\bTABLE[frame=%s,offset=%s]",frame,framespacing)) - for r, d, k in xml.elements(root,"/(mml:mtr|mml:mlabeledtr)") do - texsprint(tex.ctxcatcodes,"\\bTR") - local dk = d[k] - local at = dk.at - local rra, rca, col = at.rowalign or rowalign, at.columnalign or columnalign, 0 - for rr, dd, kk in xml.elements(dk,"/mml:mtd") do - col = col + 1 - local dk = dd[kk] - local at = dk.at - local rowspan = at.rowspan or 1 - local columnspan = at.columnspan or 1 - local cra = rowalignments [(rowaligns and rowaligns [col]) or at.rowalign or rra or "center"] - local cca = columnalignments[(columnaligns and columnaligns[col]) or at.columnalign or rca or "center"] - texsprint(tex.ctxcatcodes,format("\\bTD[align={%s,%s},nx=%s,ny=%s]$\\ignorespaces",cra,cca,columnspan,rowspan)) - xmlcprint(dk) - texsprint(tex.ctxcatcodes,"\\removeunwantedspaces$\\eTD") -- $ - end - if dk.tg == "mlabeledtr" then - texsprint(tex.ctxcatcodes,"\\bTD") - xmlcprint(xml.first(dk,"/!mml:mtd")) - texsprint(tex.ctxcatcodes,"\\eTD") - end - texsprint(tex.ctxcatcodes,"\\eTR") - end - texsprint(tex.ctxcatcodes, "\\eTABLE") - end - - end -\stopluacode +%D Remark: from now on this is a module and no longer an xtag +%D filter. There is an intermediate cleaner module but it has +%D some namespace limitations. Here we do it the \MKV\ way. \unprotect @@ -289,15 +89,13 @@ \startmodule [mathml] -%D First we load the entities: - -\usemodule[newmme] % will be replaced by math-ent or so +\ctxlua{environment.loadlucfile("x-mathml")} \unprotect \def\MMLrm{\mr} -\def\MMLseparator#1{{#1}} % nils space after separator +\def\MMLseparator#1{\removeunwantedspaces{#1}\ignorespaces} % nils space after separator %D First we define some general formula elements. @@ -350,11 +148,13 @@ %D We start with the parent elements and the option handler. - \defineXMLdirective [mathml] \setupMMLappearance % todo +% \defineXMLdirective [mathml] \setupMMLappearance % todo + +\def\xmlmathmldirective#1{\dosetvalue{MML#1}} %D In the styles, options can be set with: -\def\setupMMLappearance[#1]{\dodoubleargument\getparameters[@@MML#1]} +\def\setupMMLappearance[#1]{\dodoubleargument\getparameters[MML#1]} % no @@ because passed to lua %D We will apply inner math to all bits and pieces made up by an %D \type {apply}. @@ -364,11 +164,11 @@ %D Auxiliary MathML macros: (to be generalized) -\def\mmlfirst #1{\mmlfirst{#1}{/*}} % \xmlsnippet{1} +\def\mmlfirst #1{\xmlindex{#1}{/*}{1}} % \xmlsnippet{1} \def\mmlsecond #1{\xmlindex{#1}{/*}{2}} % \xmlsnippet{2} \def\mmlthird #1{\xmlindex{#1}{/*}{3}} % \xmlsnippet{3} \def\mmlprelast#1{\xmlindex{#1}{/*}{-2}} % -\def\mmllast #1{\xmlindex{#1}{/*}{-1}} % +\def\mmllast #1{\xmlin{#1}{/*}{-1}} % \starttexdefinition doifelsemmlfunction #1 \xmldoifelse {#1} {/mml:fn} { @@ -491,14 +291,14 @@ \edef\MMLdoR{\noexpand\right\mmlapplyclosetoken} \fi \let\MMLctempresetlist\empty -% \xmldoifelse {#1} {/mml:apply} { + \xmldoifelse {#1} {/mml:apply} { % % <apply> <apply> ... </apply> <ci> .. </ci> </apply> % \xmldoifelse {#1} {/mml:apply(mml:plus|mml:minus)} {% [a] % % yet incomplete and rather untested % % <apply> <apply> <minus/> <tan/> <cos/> </apply> <ci>x</ci> </apply> -% } {% [b] + } {% [b] % \MMLcreset -% } + } % \MMLdoL % \xmlfirst{#1}{/*} % \ifconditional\somepostponedMMLactions @@ -527,10 +327,10 @@ \xmlall{#1}{../[position()>1]} \stopxmlsetups \startxmlsetups mml:apply:mml:fn + \hbox{todo}% obsolete \stopxmlsetups \startxmlsetups mml:apply:mml:csymbol -\stopxmlsetups -\startxmlsetups mml:apply:mml:ci + \hbox{todo} \stopxmlsetups % \startsetups mmc:fn:apply @@ -577,23 +377,13 @@ % } % \stopsetups - % \defineXMLsingular - % [csymbol] - % [encoding=text, - % definitionURL=] - % {\directsetup{mmc:csymbol:apply:singular}} - - % \startsetups mmc:csymbol:apply:singular - % \lowercasestring\XMLpar{csymbol}{definitionURL}{}\to\mmcSymbolURL - % \directsetup{mmc:csymbol:\mmcSymbolURL} - % \stopsetups - % \startsetups mmc:ci:apply - % \getXMLstackdata\plusone - % \ifnum\XMLstacklevel>\plusone - % \left(\MMLcreset\flushXMLstackwith\plustwo{\MMLseparator,}\right) - % \fi - % \stopsetups +\startxmlsetups mml:apply:mml:ci + \xmlfirst{#1}{/mml:ci} + \ifnum\xmlcount{#1}{/*}>\plusone + \left(\MMLcreset\xmlconcatrange{#1}{/*}{2}{}{\MMLseparator,}\right) + \fi +\stopxmlsetups % reln @@ -686,45 +476,43 @@ \MMLcreset \getXMLentity{NegThinSpace} \MMCfnleft - \ifnum\XMLstacklevel=\plustwo\MMLccomma\fi - \flushXMLstackwith\plustwo\MMLccomma + \ifnum\XMLstacklevel=\plustwo,\fi + \flushXMLstackwith\plustwo, \MMCfnright \endgroup } } \stopsetups -% c* - - \defineXMLargument [csymbol] [encoding=text] {\XMLval{mmc:cs}{\XMLop{encoding}}{\firstofoneargument}} - %D The next definition provide a kind of plug-in mechanism (see %D the open math extension module). - \defineXMLsingular - [csymbol] - [encoding=text, - definitionURL=] - {\doifsomething{\XMLop{definitionURL}}{\directsetup{mmc:csymbol:apply}}} +% http://www.publishers.com/somename - \startsetups mmc:csymbol:apply - \begingroup - \rawXMLstacktext\plusone % still on stack, no check, just attr test - % http://www.publishers.com/SomeName - \lowercasestring\XMLpar{csymbol}{definitionURL}{}\to\mmcSymbolURL - \doifsetupselse{mmc:csymbol:} {\mmcSymbolURL} { - \expanded{\endgroup\noexpand\directsetup{mmc:csymbol:\mmcSymbolURL}} - } { - % SomeName (fallback) - \splitfilename{\XMLpar{csymbol}{definitionURL}{}} - \doifsetupselse{mmc:csymbol:\splitoffbase} { - \expanded{\endgroup\noexpand\directsetup{mmc:csymbol:\splitoffbase}} - } { - \endgroup - \XMLval{mmc:cs}{\XMLop{encoding}}{\firstofoneargument} - } - } - \stopsetups +\starttexdefinition mmlapplycsymbol #1#2#3#4 + % #1=full url, #2=name, #3=encoding, #4=text + \doifelse {#3} {text} { + {\mr #4} + } { + \doifsetupselse {mml:csymbol:#1} { + % full url + \directsetup{mml:csymbol:#1} + } { + % somename (fallback) + \doifsetupselse {mmc:csymbol:#2} { + \directsetup{mml:csymbol:#2} + } { + \XMLval{mmc:cs}{#3}{}% todo + } + } + } +\stoptexdefinition + +\startxmlsetups mml:csymbol + \ctxlua{lxml.mml.csymbol("#1")} +\stopxmlsetups + +% \startxmlsetups mml:csymbol:<url> \stopxmlsetups %D Alternative b will convert periods into comma's: %D @@ -757,7 +545,7 @@ % helpers cn \startxmlsetups mml:cn:default - \mfunction{\xmlflush{#1}} + \mathopnolimits{\xmlflush{#1}} \stopxmlsetups % helpers ci @@ -802,7 +590,7 @@ \xmlsetup{#1}{mml:cn:polar} \stopxmlsetups -% \doif\@@MMLcnalternative\v!b{\redefinemathcharacter [.][ord][mi]["3B]\relax}% +% \doif\MMLcnalternative\v!b{\redefinemathcharacter [.][ord][mi]["3B]\relax}% % % todo: number function from mmp @@ -817,15 +605,15 @@ \ifx\mmlintegerbase\empty \xmlflush{#1} \else - \doifelse \@@MMLbasesymbol \v!no { + \doifelse \MMLbasesymbol \v!no { \MMLcCNbasedata{\xmlflush{#1}} } { \MMLcCNbasedata{\xmlflush{#1}}_{ \hbox {$ - \rm + \mr \scriptscriptstyle \processaction - [\@@MMLbasesymbol] + [\MMLbasesymbol] [\v!characters=>\MMLcCNbasestring BODH, \v!text=>\MMLcCNbasestring{BIN}{OCT}{DEC}{HEX}, \s!unknown=>\mmlintegerbase] @@ -836,7 +624,7 @@ \stopxmlsetups \def\MMLcCNbasedata#1% - {\ifnum\mmlintegerbase>10 \relax{\rm#1}\else#1\fi} + {\ifnum\mmlintegerbase>10 \relax{\mr#1}\else#1\fi} \def\MMLcCNbasestring#1#2#3#4% {\ifnum\mmlintegerbase= 2 #1\else @@ -846,17 +634,17 @@ \mmlintegerbase \fi\fi\fi\fi} \startxmlsetups mml:cn:polar - \xmlsetup{#1}{mml:cn:polar:\@@MMLpolaralternative} + \xmlsetup{#1}{mml:cn:polar:\MMLpolaralternative} \stopxmlsetups \startxmlsetups mml:cn:polar:a \mathopnolimits{Polar}% ? ? ? - \left(\xmlsnippet{#1}{1}\MMLccomma\xmlsnippet{#1}{1}\right) + \left(\xmlsnippet{#1}{1},\xmlsnippet{#1}{1}\right) \stopxmlsetups \startxmlsetups mml:cn:polar:b -% {\rm e}^{\xmlsnippet{#1}{1}\mskip2mu\getXMLentity{imaginaryi}} - {\rm e}^{\xmlsnippet{#1}{1}+\xmlsnippet{#1}{3}{\rm i}} +% {\mr e}^{\xmlsnippet{#1}{1}\mskip2mu\getXMLentity{imaginaryi}} + {\mr e}^{\xmlsnippet{#1}{1}+\xmlsnippet{#1}{3}{\mr i}} \stopxmlsetups \startxmlsetups mml:cn:polar:c @@ -869,7 +657,7 @@ \stopxmlsetups \startxmlsetups mml:cn:complex - \xmlsnippet{#1}{1} + \xmlsnippet{#1}{3}{\rm i} + \xmlsnippet{#1}{1} + \xmlsnippet{#1}{3}{\mr i} \stopxmlsetups \startxmlsetups mml:cn:complex-cartesian @@ -877,9 +665,9 @@ \stopxmlsetups \startxmlsetups mml:cn:float - \doifelse \@@MMLfloatsymbol \v!no { + \doifelse \MMLfloatsymbol \v!no { % make sure that e shows up ok - \mfunction{\xmlflush{#1}} + \mathopnolimits{\xmlflush{#1}} } { % we should ignore \entities ! \edef\mmlfloatstring{\xmlflush{#1}} @@ -890,7 +678,7 @@ \mmlfloatstring \else \first - \doifelse \@@MMLfloatsymbol {dot} \cdot \times + \doifelse \MMLfloatsymbol {dot} \cdot \times 10^{\last} \fi \fi } @@ -901,19 +689,19 @@ \stopxmlsetups \startxmlsetups mml:cn:e-notation - \doifelse \@@MMLenotationsymbol \v!no { + \doifelse \MMLenotationsymbol \v!no { \xmlsnippet{#1}{1} - \unskip\mfunction{e}\ignorespaces + \unskip\mathopnolimits{e}\ignorespaces \xmlsnippet{#1}{3} } { \xmlsnippet{#1}{1} - \doifelse \@@MMLenotationsymbol {dot} \cdot + \doifelse \MMLenotationsymbol {dot} \cdot \times10^{\xmlsnippet{#1}{3}} } \stopxmlsetups \startxmlsetups mml:cn:logical - \mfunction{\xmlflush{#1}} + \mathopnolimits{\xmlflush{#1}} \stopxmlsetups \startxmlsetups mml:cn:rational @@ -935,30 +723,30 @@ \stopxmlsetups \startxmlsetups mml:interval:closed - \left[\mmlsecond{#1}\MMLseparator\@@MMLintervalseparator\mmlthird{#1}\right] + \left[\mmlfirst{#1}\MMLseparator\MMLintervalseparator\mmlsecond{#1}\right] \stopxmlsetups \startxmlsetups mml:interval:open-closed - \doifelse \@@MMLintervalalternative \v!b { - \left<\mmlsecond{#1}\MMLseparator\@@MMLintervalseparator\mmlthird{#1}\right] + \doifelse \MMLintervalalternative \v!b { + \left<\mmlfirst{#1}\MMLseparator\MMLintervalseparator\mmlsecond{#1}\right] } { - \left(\mmlsecond{#1}\MMLseparator\@@MMLintervalseparator\mmlthird{#1}\right] + \left(\mmlfirst{#1}\MMLseparator\MMLintervalseparator\mmlsecond{#1}\right] } \stopxmlsetups \startxmlsetups mml:interval:closed-open - \doifelse \@@MMLintervalalternative \v!b { - \left[\mmlsecond{#1}\MMLseparator\@@MMLintervalseparator\mmlthird{#1}\right> + \doifelse \MMLintervalalternative \v!b { + \left[\mmlfirst{#1}\MMLseparator\MMLintervalseparator\mmlsecond{#1}\right> } { - \left[\mmlsecond{#1}\MMLseparator\@@MMLintervalseparator\mmlthird{#1}\right) + \left[\mmlfirst{#1}\MMLseparator\MMLintervalseparator\mmlsecond{#1}\right) } \stopxmlsetups \startxmlsetups mml:interval:open - \doifelse \@@MMLintervalalternative \v!b { - \left<\mmlsecond{#1}\MMLseparator\@@MMLintervalseparator\mmlthird{#1}\right> + \doifelse \MMLintervalalternative \v!b { + \left<\mmlfirst{#1}\MMLseparator\MMLintervalseparator\mmlsecond{#1}\right> } { - \left(\mmlsecond{#1}\MMLseparator\@@MMLintervalseparator\mmlthird{#1}\right) + \left(\mmlfirst{#1}\MMLseparator\MMLintervalseparator\mmlsecond{#1}\right) } \stopxmlsetups @@ -981,17 +769,22 @@ \xmlsetup{#1}{\xmlfilter{#1}{/mml:apply/*/name(1)}} \stopxmlsetups -\startxmlsetups xml:mmc:process +\startxmlsetups xml:mml:inverse \xmlsetsetup{\xmldocument}{mml:apply/mml:apply/mml:inverse/../../..}{mml:apply:inverse} \stopxmlsetups -\xmlregistersetup{xml:mmc:process} +\xmlregistersetup{xml:mml:inverse} % condition % maybe a fast \xmlnonfirst -\startxmlsetups mmc:condition +\startxmlsetups mml:bvar \xmlflush{#1} \stopxmlsetups +\startxmlsetups mml:lowlimit \xmlflush{#1} \stopxmlsetups +\startxmlsetups mml:uplimit \xmlflush{#1} \stopxmlsetups +\startxmlsetups mml:degree \xmlflush{#1} \stopxmlsetups + +\startxmlsetups mml:condition % \xmldoif {#1} {/mml:bvar} { % \xmlfirst{#1}{/mml:bvar}\mid % } @@ -1003,7 +796,7 @@ \setupMMLappearance[declare][\c!state=\v!start] \startxmlsetups mml:declare - \doif \@@MMLdeclarestate \v!start { + \doif \MMLdeclarestate \v!start { \mathopnolimits{declare} \xmlindex{#1}{/*}{1} \ifnum \xmlcount{#1}{/} > \plusone @@ -1019,15 +812,15 @@ \setupMMLappearance[lambda][\c!alternative=b] -\startxmlsetups mmc:lambda +\startxmlsetups mml:lambda \begingroup - \doifelse \@@MMLlambdaalternative \v!a { + \doifelse \MMLlambdaalternative \v!a { \lambda\left(\xmlconcat{#1}{/!mml:lambda}{\MMLseparator,}\left) } { \ifnum \xmlcount {#1} {/mml:bvar} > \plusone \left(\xmlconcat{#1}{/mml:bvar}{\MMLseparator,}\right) \else - \xmlfirstnamed{#1}{bvar} + \xmlfirst{#1}{/mml:bvar} \fi \mapsto \MMLcreset @@ -1043,9 +836,9 @@ \MMLcreset % \let\MMLcCIfunction\firstofoneargument % brrr ? ? ? \doifelsemmlfunction { - \left(\xmlconcatrange{#1}{2}{}{\circ}\right) + \left(\xmlconcatrange{#1}{/*}{2}{}{\circ}\right) } { - \xmlconcatrange{#1}{2}{}{\circ} + \xmlconcatrange{#1}{/*}{2}{}{\circ} } \endgroup \stopxmlsetups @@ -1058,12 +851,12 @@ \startxmlsetups mml:piecewise \processaction - [\@@MMLpieceseparator] - [ \v!yes=>\def\theMMLpieceseparator{,\@col@amp@}, - \v!no=>\let\theMMLpieceseparator\@col@amp@, - \s!default=>\let\theMMLpieceseparator\@col@amp@, - \s!unknown=>\def\theMMLpieceseparator{\,\,\hbox{\@@MMLpieceseparator}\,\,}] - \cases \xmlflush{#1} + [\MMLpieceseparator] + [ \v!yes=>\def\theMMLpieceseparator{,&}, + \v!no=>\def\theMMLpieceseparator{&}, + \s!default=>\def\theMMLpieceseparator{&}, + \s!unknown=>\def\theMMLpieceseparator{\,\,\hbox{\MMLpieceseparator}\,\,}] + \cases{\xmlflush{#1}} \stopxmlsetups \startxmlsetups mml:piece @@ -1071,7 +864,8 @@ \stopxmlsetups \startxmlsetups mml:otherwise - \xmlflush{#1}\MMLcPIECEseparator\@col@amp@\mathematics{otherwise}\crcr +% \xmlflush{#1}\MMLcPIECEseparator&{\mr otherwise}\crcr + \xmlflush{#1}&{\mr otherwise}\crcr \stopxmlsetups % end of piece @@ -1090,10 +884,10 @@ \startxmlsetups mml:divide \advance\mmldividelevel\plusone - \doifelse \@@MMLdividealternative \v!b { + \doifelse \MMLdividealternative \v!b { \mmlsecond{#1}/\mmlthird{#1} } { - \ifnum \mmldividelevel > \@@MMLdividelevel \relax % threshold + \ifnum \mmldividelevel > \MMLdividelevel \relax % threshold \mmlsecond{#1}/\mmlthird{#1} \else \MMLcreset @@ -1105,20 +899,16 @@ % min max -\startxmlsetups mml:min - \xmldoifelse {#1} {/mml:bvar} { - {}_{\xmlfirst{#1}{/mml:bvar}} - } { - } - \left\{\xmlconcat{#1}{/!(mml:bvar\string|mml:min)}{\wedge}{\MMLseparator,}\right\} -\stopxmlsetups +\startxmlsetups mml:min \mathopnolimits{min} \xmlsetup{#1}{mml:minmax} \stopxmlsetups +\startxmlsetups mml:max \mathopnolimits{max} \xmlsetup{#1}{mml:minmax} \stopxmlsetups -\startxmlsetups mml:max - \xmldoifelse {#1} {/mml:bvar} { +\startxmlsetups mml:minmax + \xmldoif {#1} {/mml:bvar} { {}_{\xmlfirst{#1}{/mml:bvar}} - } { } - \left\{\xmlconcat{#1}{/!(mml:bvar\string|mml:max)}{\wedge}{\MMLseparator,}\right\} + \left\{ + \xmlconcat{#1}{/!(mml:bvar\string|mml:max\string|mml:min)}{\MMLseparator,} + \right\} \stopxmlsetups % minus plus @@ -1135,7 +925,7 @@ \newcount\mmlpluscounter \startxmlsetups mml:plus - \doifelse \@@MMLsignreduction \v!yes { + \doifelse \MMLsignreduction \v!yes { \MMLdoL \xmlsetup{#1}{mml:plus:reset} \xmlcommand{#1}{/!mml:plus}{mml:plus:body} @@ -1176,7 +966,7 @@ \newcount\mmlminuscounter \startsetups mml:minus - \doifelse \@@MMLsignreduction \v!yes { + \doifelse \MMLsignreduction \v!yes { } { } \ifnum\xmlcount{#1}{/!mml:minus}=\plusone @@ -1210,7 +1000,7 @@ \startxmlsetups mml:power \xmldoifelse {#1} {/mml:apply} { - \doifelse \@@MMLpowerreduction \v!yes { + \doifelse \MMLpowerreduction \v!yes { \xmldoifelse {#1} {/(\MMLcfunctionlist)} { \gdef\MMLpowerelement{\mmlthird{#1}}% postpone, no xdef \MMLcreset\mmlsecond{#1} @@ -1235,26 +1025,26 @@ \startxmlsetups mml:times \setMMLcreset{\MMLcfunctionlist\string|\MMLcconstructlist}% - \doifelse\@@MMLtimesauto\v!no { - \let\@@MMLtimes@@symbol\@@MMLtimessymbol + \doifelse\MMLtimesauto\v!no { + \let\MMLtimes@@symbol\MMLtimessymbol } { \xmldoifelse {#1} {/mml:cn[name(1) == 'mml:cn']} {% name(1) is next one - \doifinsetelse\@@MMLtimessymbol{\v!yes,\v!no} { - \let\@@MMLtimes@@symbol\v!yes + \doifinsetelse\MMLtimessymbol{\v!yes,\v!no} { + \let\MMLtimes@@symbol\v!yes } { - \let\@@MMLtimes@@symbol\@@MMLtimessymbol + \let\MMLtimes@@symbol\MMLtimessymbol } } { - \let\@@MMLtimes@@symbol\@@MMLtimessymbol + \let\MMLtimes@@symbol\MMLtimessymbol } } - \doifelse\@@MMLtimes@@symbol\v!yes { + \doifelse\MMLtimes@@symbol\v!yes { \xmlconcat{#1}{/!mml:times}{\times} } { - \doifelse\@@MMLtimes@@symbol{dot} { + \doifelse\MMLtimes@@symbol{dot} { \xmlconcat{#1}{/!mml:times}{\cdot} } { - \doifelse\@@MMLtimes@@symbol{times} { + \doifelse\MMLtimes@@symbol{times} { \xmlconcat{#1}{/!mml:times}{\times} } { \xmlall{#1}{/!mml:times} @@ -1268,7 +1058,7 @@ \startxmlsetups mml:root \xmldoifelse {#1} {/mml:degree} { \root - \doifnot\@@MMLrootsymbol\v!no{\MMLcreset\xmltext{#1}{/mml:degree}} + \doifnot\MMLrootsymbol\v!no{\MMLcreset\xmltext{#1}{/mml:degree}} \of } { \sqrt @@ -1286,11 +1076,11 @@ % and or xor implies, not -\startxmlsetups mml:and \xmlconcat{#1}{/!mml:and} {2}{}{\wedge} \stopxmlsetups -\startxmlsetups mml:or \xmlconcat{#1}{/!mml:or} {2}{}{\vee} \stopxmlsetups -\startxmlsetups mml:xor \xmlconcat{#1}{/!mml:xor} {2}{}{\mathopnolimits{xor}} \stopxmlsetups -\startxmlsetups mml:implies \xmlconcat{#1}{/!mml:implies}{2}{}{\Rightarrow} \stopxmlsetups -\startxmlsetups mml:not \neg \xmlall {#1}{/!mml:not} \stopxmlsetups +\startxmlsetups mml:and \xmlconcat{#1}{/!mml:and} {\wedge} \stopxmlsetups +\startxmlsetups mml:or \xmlconcat{#1}{/!mml:or} {\vee} \stopxmlsetups +\startxmlsetups mml:xor \xmlconcat{#1}{/!mml:xor} {\mathopnolimits{xor}} \stopxmlsetups +\startxmlsetups mml:implies \xmlconcat{#1}{/!mml:implies}{\Rightarrow} \stopxmlsetups +\startxmlsetups mml:not \neg \xmlall {#1}{/!mml:not} \stopxmlsetups % forall exists @@ -1393,7 +1183,7 @@ \startxmlsetups mml:relation \edef\mmlapplyaction{\xmlfilter{#1}{/*/name()}} - \MMLcreset \xmlsetup{#1}{mml:relation:\xmlattdef{#1}{align}{no}} + \MMLcreset \xmlsetup{#1}{mml:relation:\xmlattdef{#1}{align}{\MMLrelationalign}} \stopxmlsetups \startxmlsetups mml:relation:default @@ -1444,7 +1234,7 @@ \setupMMLappearance[int][\c!location=\v!top] -\def\doMMLlimits#1{\doifelsevalue{@@MML#1\c!location}\v!top\limits\nolimits} +\def\doMMLlimits#1{\doifelsevalue{MML#1\c!location}\v!top\limits\nolimits} \startxmlsetups mml:int \MMLcreset @@ -1478,16 +1268,13 @@ \xmlfirst{#1}{/mml:ci} } \xmldoifelse {#1} {/mml:bvar} { - \thinspace \mfunction{d} \xmlfirst{#1}{/mml:bvar} + \thinspace {\mr d} \xmlfirst{#1}{/mml:bvar} } { % nothing } \stopxmlsetups - \setupMMLappearance[diff][\c!location=\v!top,\c!alternative=\v!a] - - \defineXMLcommand [diff] {\directsetup{mmc:diff}} - \defineXMLcommand [partialdiff] {\directsetup{mmc:partialdiff}} +\setupMMLappearance[diff][\c!location=\v!top,\c!alternative=\v!a] % \setupMMLappearance[diff][alternative=b] % @@ -1505,118 +1292,104 @@ % </apply></math> % \stopXMLdata - \startsetups mmc:diff - \MMLcreset - \doifelse\@@MMLdiffalternative\v!a { - \XMLdoifonstackelse{lambda} { - % a special case (mathadore/openmath) - \begingroup - \defineXMLsave[ci] - \defineXMLsave[cn] - \defineXMLprocess[lambda] - \defineXMLprocess[bvar] - \frac { - d^{\XMLfirstnamed{bvar}\XMLflush{cn}}{\XMLfirstnamed{lambda}\XMLflush{ci}} - } { - d{\XMLfirstnamed{bvar}\XMLflush{ci}}^{\XMLfirstnamed{bvar}\XMLflush{cn}} - } - \endgroup +\startxmlsetups mml:diff + \MMLcreset + \doifelse \MMLdiffalternative \v!a { + \xmldoifelse {#1} {/mml:lambda} { + % a special case (mathadore/openmath) + \frac { + d^{\xmlfirst{#1}{/mml:bvar}\xmlfirst{#1}{/mml:cn}}{\xmlfirst{#1}{/mml:lambda}\xmlfirst{#1}{/mml:ci}} + } { + d{\xmlfirst{#1}{/mml:bvar}\xmlfirst{#1}{/mml:ci}}^{\xmlfirst{#1}{/mml:bvar}\xmlfirst{#1}{/mml:cn}} + } + } { + \xmldoifelse {#1} {/mml:bvar} { + \frac { + {\mr d}{ + \xmldoifelse {#1} {/mml:degree} { + ^{\xmlconcat{#1}{/mml:degree}\empty} } { - \XMLdoifonstackelse{bvar} { - \frac { - \XMLdoifonstackelse{degree} { - \collectXMLnamedstack{degree}\empty - } { - \collectXMLnamedstacknamed{bvar}{degree}+ - } - \mfunction{\getXMLentity{mathematicald}} - ^{\the\XMLRtoks} - \doif\@@MMLdifflocation\v!top { - \XMLdoifonstackelse{ci} { - \XMLfirstnamed{ci} - } { - \MMLcreset\XMLfirstnamed{apply} - } - } - } { - \mfunction{\getXMLentity{mathematicald}} - \begingroup - \defineXMLsave[degree] - \XMLfirstnamed{bvar} - \doifXMLdata{degree} { - ^{\XMLflush{degree}} - } - \endgroup - } - \doifnot\@@MMLdifflocation\v!top { - \left(\MMLcreset\XMLfirstnamed{apply,ci}\right) - } - } { - \flushXMLstackfrom\plustwo^\prime - } - } - } { - \MMLcreset - \XMLfirstnamed{apply,ci} - % there can be problems with nested diff's: ^^{} error - % so we add an empty group here - {}^ - { - \XMLdoifonstackelse{degree} { - \defXMLfirstnamedtext\ascii{degree} - \dorecurse\ascii\prime - } { - \prime + \xmldoif {#1} {/mml:bvar/mml:degree} { + ^{\xmlconcat{#1}{/mml:bvar/mml:degree}+} } } } - \stopsetups - - \startsetups mmc:partialdiff - \XMLdoifonstackelse{list} { - \getXMLentity{capitaldifferentiald}_{ - \begingroup - \setfalse\mmllistdelimiters - \XMLallnamed{list} - \endgroup - } - \XMLfirstnamed{apply,reln,ci,cn} - } { - \XMLdoifonstackelse{bvar} { - \frac { - \XMLdoifonstackelse{degree} { - \collectXMLnamedstack{degree}\empty - } { - \collectXMLnamedstacknamed{bvar}{degree}+ - } - \getXMLentity{differentiald}^{\the\XMLRtoks} - \MMLcreset - \XMLfirstnamed{apply,reln,ci,cn} - } { - \defineXMLnested[bvar] - {\directsetup{mmc:bvar:diff:start}} - {\directsetup{mmc:bvar:diff:stop}} - \XMLfirstnamed{bvar} - } + \doif \MMLdifflocation \v!top { + \xmldoifelse {#1} {/mml:ci} { + \xmlfirst{#1}{/mml:ci} } { - \XMLfirstnamed{apply,reln,ci,cn} + \MMLcreset + \xmlfirst{#1}{/mml:apply} } } - \stopsetups - - \startsetups mmc:bvar:diff:start - \begingroup - \stopsetups + } { + {\mr d} + \xmlfirst{#1}{/mml:bvar/!mml:degree} + \xmldoif {#1} {/mml:bvar/mml:degree} { + ^{\xmlfirst{#1}{/mml:bvar/mml:degree}} + } + } + \doifnot \MMLdifflocation \v!top { + \left(\MMLcreset\xmlfirst{#1}{/(mml:apply\string|mml:ci)}\right) + } + } { + \xmlconcatrange{#1}{/*}{2}{}^\prime + } + } + } { + \MMLcreset + \xmlfirst{#1}{/(mml:apply\string|mml:ci)} + % there can be problems with nested diff's: ^^{} error + % so we add an empty group here + {}^ + { + \xmldoifelse {#1} {/mml:degree} { + \edef\mmldegree{\xmlfirst{#1}{/mml:degree/mml:cn}} + \ifx\mmldegree\empty + % what to do here + \else + \dorecurse\mmldegree\prime + \fi + } { + \prime + } + } + } +\stopxmlsetups - \startsetups mmc:bvar:diff:stop - \getXMLentity{differentiald}\XMLfirstnamed{apply,reln,ci,cn} - \XMLdoifonstackelse{degree} { - ^{\XMLfirstnamed{degree}} +\startxmlsetups mml:partialdiff + \xmldoifelse {#1} {/mml:list} { + {\mr D}_{ + \begingroup + \setfalse\mmllistdelimiters + \xmlall{#1}{/mml:list} + \endgroup + } + \xmlfirst{#1}{/(mml:apply\string|mml:reln\string|mml:ci\string|mml:cn)} + } { + \xmldoifelse {#1} {/mml:bvar} { + \frac { + {\mr d}^{ + \xmldoifelse {#1} {/mml:degree} { + \xmlconcat{#1}{/mml:degree}\empty } { - % nothing + \xmlconcat{#1}{/mml:bvar/mml:degree}+ } - \endgroup - \stopsetups + } + \MMLcreset + \xmlfirst{#1}{/(mml:apply\string|mml:reln\string|mml:ci\string|mml:cn)} + } { + \xmlfirst{#1}{/mml:bvar} + {\mr d}\xmlfirst{#1}{/(mml:apply\string|mml:reln\string|mml:ci\string|mml:cn)} + \xmldoif {#1} {/mml:degree} { + ^{\xmlfirst{#1}{/mml:degree}} + } + } + } { + \xmlfirst{#1}{/(mml:apply\string|mml:reln\string|mml:ci\string|mml:cn)} + } + } +\stopxmlsetups % option: to be discussed with taco/aditya: all math functions \mathentity % @@ -1627,25 +1400,25 @@ \startxmlsetups mml:divergence \mathopnolimits{div} \xmlall{#1}{/!mml:divergence} \stopxmlsetups \startxmlsetups mml:grad \mathopnolimits{grad} \xmlall{#1}{/!mml:grad} \stopxmlsetups \startxmlsetups mml:curl \mathopnolimits{curl} \xmlall{#1}{/!mml:curl} \stopxmlsetups -\startxmlsetups mml:laplacian \mathopnolimits{\nabla^2} \xmlall{#1}{/!mml:laplacian} \stopxmlsetups +\startxmlsetups mml:laplacian \nabla^2 \xmlall{#1}{/!mml:laplacian} \stopxmlsetups \startxmlsetups mml:ident \mathopnolimits{identity} \xmlall{#1}{/!mml:ident} \stopxmlsetups \setupMMLappearance[domain] [symbol=] \setupMMLappearance[codomain][symbol=] \startxmlsetups mml:domain - \doifelsenothing \@@MMLdomainsymbol { + \doifelsenothing \MMLdomainsymbol { \mathopnolimits{domain}\MMLcreset\xmlall{#1}{/!mml:domain} } { - \@@MMLdomainsymbol_{\xmlall{#1}{/!mml:domain}} + \MMLdomainsymbol_{\xmlall{#1}{/!mml:domain}} } \stopxmlsetups \startxmlsetups mml:codomain - \doifelsenothing \@@MMLcodomainsymbol { + \doifelsenothing \MMLcodomainsymbol { \mathopnolimits{codomain}\MMLcreset\xmlall{#1}{/!mml:codomain} } { - \@@MMLcodomainsymbol_{\xmlall{#1}{/!mml:codomain}} + \MMLcodomainsymbol_{\xmlall{#1}{/!mml:codomain}} } \stopxmlsetups @@ -1653,12 +1426,13 @@ \startxmlsetups mml:set \left\{ - \xmldoif {#1} {/mml:condition} { + \xmldoifelse {#1} {/mml:condition} { \xmlfirst{#1}{/mml:bvar}\,\middle\vert\,\xmlfirst{#1}{/mml:condition} } { \xmlconcat{#1}{/!mml:set}{\MMLseparator,} } \right\} + \relax % needed \stopxmlsetups \settrue\mmllistdelimiters @@ -1697,11 +1471,11 @@ \setupMMLappearance[sum] [\c!location=\v!top] \setupMMLappearance[product][\c!location=\v!top] -\mapXMLvalue {mml:sumproc} {sum} {\sum} -\mapXMLvalue {mml:sumproc} {product} {\prod} +\mapXMLvalue {mml:sumprod} {sum} {\sum} +\mapXMLvalue {mml:sumprod} {product} {\prod} -\startxmlsetups mml:sum \xmlsetup{#1}{mml:sumprod} \stopxmlsetups -\startxmlsetups mml:product \xmlsetup{#1}{mml:sumprod} \stopxmlsetups +\startxmlsetups mml:sum \edef\mmlsumprodname{sum} \xmlsetup{#1}{mml:sumprod} \stopxmlsetups +\startxmlsetups mml:product \edef\mmlsumprodname{product} \xmlsetup{#1}{mml:sumprod} \stopxmlsetups \def\mmlstackedsubscripts#1% {\vbox @@ -1745,7 +1519,7 @@ \fi } \MMLcreset - \XMLval{mml:sumproc}{\xmltag{#1}}{}\doMMLlimits{#1}\mmlsumprodupper\mmlsumprodlower + \XMLval{mml:sumprod}{\mmlsumprodname}{}\doMMLlimits\mmlsumprodname\mmlsumprodupper\mmlsumprodlower \MMLcreset \xmldoifelse {#1} {/mml:lambda/mml:apply} { \xmlfirst{#1}{/mml:lambda/mml:apply}% a bit of open math conversion mess @@ -1759,7 +1533,7 @@ \startxmlsetups mml:limit \MMLcreset \lim - \doMMLlimits {#1} {limit}_{ + \doMMLlimits {limit}_{ \MMLcreset \xmldoifelse {#1} {/mml:condition} { \xmlfirst{#1}{/mml:condition} @@ -1774,7 +1548,7 @@ % a bit of open math conversion mess, lambda needed for openmath, ok? \MMLcreset \xmlfirst{#1}{/mml:lambda/mml:apply} - \xmlfirst{#1}{/(mml:apply\string|\mml:lambda} + \xmlfirst{#1}{/(mml:apply\string|mml:lambda)} \endgroup \stopxmlsetups @@ -1795,28 +1569,28 @@ \setupMMLappearance[log][\c!location=\v!right] \startxmlsetups mml:exp -% {\rm e}^{\xmlfirst{#1}{/mml:apply\string|mml:reln\string|mml:ci\string|mml:cn}} - {\rm e}^{\xmlfirst{#1}{/!mml:exp}} +% {\mr e}^{\xmlfirst{#1}{/mml:apply\string|mml:reln\string|mml:ci\string|mml:cn}} + {\mr e}^{\xmlfirst{#1}{/!mml:exp}} \stopxmlsetups \startxmlsetups mml:log \xmldoifelse {#1} {/mml:logbase} { - \doifelse \@@MMLloglocation \v!left { + \doifelse \MMLloglocation \v!left { \mathop { - {}^{\xmlfirst{#1}{/mml:logbase}}\negthinspace\mfunction{log} + {}^{\xmlfirst{#1}{/mml:logbase}}\negthinspace\mathopnolimits{log} } } { - \mfunction{log}_{\xmlfirst{#1}{/mml:logbase}} + \mathopnolimits{log}_{\xmlfirst{#1}{/mml:logbase}} } } { - \mfunction{log} + \mathopnolimits{log} } \MMLcreset \xmlsetup{#1}{mml:function} \stopxmlsetups \startxmlsetups mml:ln - \mfunction {ln} + \mathopnolimits{ln} \xmlsetup{#1}{mml:function} \stopxmlsetups @@ -1835,7 +1609,7 @@ \xmlfirst{#1}{/(mml:apply\string|mml:reln\string|mml:ci\string|mml:cn)}^{\xmlfirst{#1}{/mml:degree}} \right\rangle \xmldoif {#1} {mml:momentabout} { - _{\xmlfirst{mml:momentabout}} + _{\xmlfirst{#1}{mml:momentabout}} } \stopxmlsetups @@ -1843,16 +1617,16 @@ \setupMMLappearance [vector] [\c!direction=\v!horizontal,\c!separator={,}] -\startxmlsetups mml:vector:start +\startxmlsetups mml:vector \begingroup \ifnum\xmlcount{#1}{/*}>\plusone - \doifelse\@@MMLvectordirection\v!horizontal { - \left(\xmlconcat{#1}{/*}{\MMLseparator\@@MMLvectorseparator}\right) + \doifelse\MMLvectordirection\v!horizontal { + \left(\xmlconcat{#1}{/*}{\MMLseparator\MMLvectorseparator}\right) } { - \MMLcreset\left(\matrix{\xmlconcat{#1}{/*}{\MMLseparator\@@MMLvectorseparator}}\right) + \MMLcreset\left(\matrix{\xmlconcat{#1}{/*}{\MMLseparator\MMLvectorseparator}}\right) } \else - \overrightarrow{\charhtstrut\mmlsecond{#1}} + \overrightarrow{\charhtstrut\mmlfirst{#1}} \fi \endgroup \stopxmlsetups @@ -1879,7 +1653,7 @@ \stopxmlsetups \startxmlsetups mml:matrixrow:do - \xmlconcat{#1}{/*}\crcr + \xmlconcat{#1}{/*}{&}\crcr \stopxmlsetups \startxmlsetups mml:determinant @@ -1890,7 +1664,7 @@ \stopxmlsetups \startxmlsetups mml:transpose - \mmlsecond{#1}^{\mfunction{T}} + \mmlsecond{#1}^{\mathopnolimits{T}} \stopxmlsetups \startxmlsetups mml:selector @@ -1907,6 +1681,8 @@ \xmlfirst{#1}{/(mml:annotation\string|apply)} \stopxmlsetups +\usemodule[m][calcmath] + \startxmlsetups mml:annotation \xmldoifelse {#1} {[oneof(@encoding,'TeX','tex','TEX','ConTeXt','context','CONTEXT','ctx')]} { \begingroup @@ -1915,7 +1691,7 @@ \endgroup } { \xmldoifelse {#1} {[oneof(@encoding,'calcmath','cm')]} { - % to be supported + \calcmath{\xmlflush{#1}} } { % unsupported } @@ -1928,61 +1704,69 @@ % misc -\startxmlsetups mml:integers \integers \stopxmlsetups -\startxmlsetups mml:reals \reals \stopxmlsetups -\startxmlsetups mml:rationals \rationals \stopxmlsetups -\startxmlsetups mml:naturalnumbers \naturalnumbers \stopxmlsetups -\startxmlsetups mml:complexes \complexes \stopxmlsetups -\startxmlsetups mml:primes \primes \stopxmlsetups -\startxmlsetups mml:exponentiale \mathop{\rm e} \stopxmlsetups -\startxmlsetups mml:imaginaryi \mathop{\rm i} \stopxmlsetups -\startxmlsetups mml:notanumber \mathop{\mfunction{NaN}} \stopxmlsetups -\startxmlsetups mml:true \mathop{\mfunction{true}} \stopxmlsetups -\startxmlsetups mml:false \mathop{\mfunction{false}} \stopxmlsetups -\startxmlsetups mml:emptyset \mathop{\O} \stopxmlsetups -\startxmlsetups mml:pi \pi \stopxmlsetups -\startxmlsetups mml:eulergamma \gamma \stopxmlsetups -\startxmlsetups mml:infinity \infty \stopxmlsetups +\startxmlsetups mml:integers \integers \stopxmlsetups +\startxmlsetups mml:reals \reals \stopxmlsetups +\startxmlsetups mml:rationals \rationals \stopxmlsetups +\startxmlsetups mml:naturalnumbers \naturalnumbers \stopxmlsetups +\startxmlsetups mml:complexes \complexes \stopxmlsetups +\startxmlsetups mml:primes \primes \stopxmlsetups +\startxmlsetups mml:exponentiale \mathopnolimits{e} \stopxmlsetups +\startxmlsetups mml:imaginaryi \mathopnolimits{i} \stopxmlsetups +\startxmlsetups mml:notanumber \mathopnolimits{NaN} \stopxmlsetups +\startxmlsetups mml:true \mathopnolimits{true} \stopxmlsetups +\startxmlsetups mml:false \mathopnolimits{false} \stopxmlsetups +\startxmlsetups mml:emptyset \mathopnolimits{\O} \stopxmlsetups +\startxmlsetups mml:pi \pi \stopxmlsetups +\startxmlsetups mml:eulergamma \gamma \stopxmlsetups +\startxmlsetups mml:infinity \infty \stopxmlsetups % gonio functions \setupMMLappearance[function][\c!reduction=\v!yes] -\startxmlsetups mml:sin \mfunction {sin}\xmlsetup{#1}{mml:function} \stopxmlsetups -\startxmlsetups mml:sinh \mfunction{sinh}\xmlsetup{#1}{mml:function} \stopxmlsetups -\startxmlsetups mml:cos \mfunction {cos}\xmlsetup{#1}{mml:function} \stopxmlsetups -\startxmlsetups mml:cosh \mfunction{cosh}\xmlsetup{#1}{mml:function} \stopxmlsetups -\startxmlsetups mml:tan \mfunction {tan}\xmlsetup{#1}{mml:function} \stopxmlsetups -\startxmlsetups mml:tanh \mfunction{tanh}\xmlsetup{#1}{mml:function} \stopxmlsetups -\startxmlsetups mml:cot \mfunction {cot}\xmlsetup{#1}{mml:function} \stopxmlsetups -\startxmlsetups mml:coth \mfunction{coth}\xmlsetup{#1}{mml:function} \stopxmlsetups -\startxmlsetups mml:csc \mfunction {csc}\xmlsetup{#1}{mml:function} \stopxmlsetups -\startxmlsetups mml:csch \mfunction{csch}\xmlsetup{#1}{mml:function} \stopxmlsetups -\startxmlsetups mml:sec \mfunction {sec}\xmlsetup{#1}{mml:function} \stopxmlsetups -\startxmlsetups mml:sech \mfunction{sech}\xmlsetup{#1}{mml:function} \stopxmlsetups +% todo: \mfunction which adapts itself when registered as command + +\startxmlsetups mml:sin \mathopnolimits {sin}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:sinh \mathopnolimits{sinh}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:cos \mathopnolimits {cos}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:cosh \mathopnolimits{cosh}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:tan \mathopnolimits {tan}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:tanh \mathopnolimits{tanh}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:cot \mathopnolimits {cot}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:coth \mathopnolimits{coth}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:csc \mathopnolimits {csc}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:csch \mathopnolimits{csch}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:sec \mathopnolimits {sec}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:sech \mathopnolimits{sech}\xmlsetup{#1}{mml:function} \stopxmlsetups \startxmlsetups mml:function \ifconditional\xmlinversefunction^{-1}\fi\setfalse\xmlinversefunction \xmlsetup{#1}{mml:function:argument} \stopxmlsetups - \startxmlsetups mml:function:argument - % \doifelse \@@MMLfunctionreduction \v!yes { - % \xmldoifelse {#1} {/mml:apply} { - % \xmldoifelse {#1} {/(\MMLcfunctionlist\string|mml:divide} \donefalse \donetrue - % } { - % \donefalse - % } - % } { - % \donetrue - % } - % beware, we still flush from 2 up - % \ifdone - \left(\MMLcreset\xmlall{#1}{/[position()>1]}\right) - % \else - % \MMLcreset\flushXMLstackfrom\plustwo - % \fi - \stopxmlsetups +\startxmlsetups mml:function:argument + \doifelse \MMLfunctionreduction \v!yes { + \xmldoifelse {#1} {/mml:apply} { + \xmldoifelse {#1} {/mml:apply/(\MMLcfunctionlist\string|mml:divide)} + \donefalse + \donetrue + } { + \donefalse + } + } { + \donetrue + } + % beware, we still flush from 2 up + \ifdone + \left( + \MMLcreset + \xmlall{#1}{/[position()>1]}% \xmlconcatrange{#1}{/*}{2}{}\empty + \right) + \else + \MMLcreset + \xmlall{#1}{/[position()>1]} + \fi +\stopxmlsetups % PRESENTATION MATHML % @@ -2030,7 +1814,7 @@ \stoptexdefinition \starttexdefinition applymmlsometext #1#2 - applymmlmathbackground {#1} { + \applymmlmathbackground {#1} { \applymmlmathcolor {#1} { \setmmlmathstyle {#1} \ignorespaces#2\removeunwantedspaces @@ -2060,50 +1844,45 @@ % setups \startxmlsetups mml:mi % todo: mathvariant mathsize mathcolor mathbackground - \ctxlua{lxml.mml.prepare_identifier("#1","*")} + \ctxlua{lxml.mml.mi("#1","*")} \stopxmlsetups \startxmlsetups mml:mn % todo: mathvariant mathsize mathcolor mathbackground \begingroup - \mr \ctxlua{lxml.mml.prepare_number("#1","*")}% no \hbox, would be ok for . , but spoils rest + \mr \ctxlua{lxml.mml.mn("#1","*")}% no \hbox, would be ok for . , but spoils rest \endgroup \stopxmlsetups \startxmlsetups mml:mo - \ctxlua{lxml.mml.prepare_operator("#1","*")} + \ctxlua{lxml.mml.mo("#1","*")} \stopxmlsetups \startxmlsetups mml:mfenced % {} around separator is needed for spacing - \edef\mmlfencedopen {\xmlatt{#1}{open}} - \edef\mmlfencedclose {\xmlatt{#1}{close}} - \edef\mmlfencedseparators{\xmlatt{#1}{separators}} - \ifx \mmlfencedseparators \empty - \def\mmlfencedseparators{,} - \fi - \ifx \mmlfencedopen \empty - \left. - \else - \left\mmlfencedopen - \fi - \ctxlua{lxml.mml.connect("#1","/*","\mmlfencedseparators")}% - \ifx \mmlfencedclose \empty - \right. - \else - \right\mmlfencedclose - \fi + \def\MMLleft {\left }% weird + \def\MMLright{\right} + \ctxlua{lxml.mml.mfenced("#1","/*")} \stopxmlsetups \startxmlsetups mml:menclose % notation=..... - \doifelse {\xmlatt{#1}{notation}} {longdiv} { - \overline{)\xmlflush{#1}} + \edef\mmlmenclosenotation{\xmlattdef{#1}{notation}{longdiv}} + \doifelse \mmlmenclosenotation {longdiv} { + \overline{\left)\xmlflush{#1}\right.} } { - \xmlflush{#1} + \doifelse \mmlmenclosenotation {actuarial} { + \overline{\left.\xmlflush{#1}\right|} + } { + \doifelse \mmlmenclosenotation {radical} { + \sqrt{\xmlflush{#1}} + } { + \xmlflush{#1} + } + } } \stopxmlsetups -\mapXMLvalue {mfrac:linethickness} {thin} {.2pt} -\mapXMLvalue {mfrac:linethickness} {medium} {.4pt} -\mapXMLvalue {mfrac:linethickness} {thick} {.8pt} +\mapXMLvalue {mml:mfrac:linethickness} {thin} {.2pt} +\mapXMLvalue {mml:mfrac:linethickness} {medium} {.4pt} +\mapXMLvalue {mml:mfrac:linethickness} {thick} {.8pt} \startxmlsetups mml:mfrac % dodo: handle linethickness in lua + unit \begingroup @@ -2114,16 +1893,16 @@ \mathpunct{\kern-.2ex\left.\middle/\right.\kern-.25ex} \mmlsecond{#1} } { - \frac{\xmlfirst{#1}}{\mmlsecond{#1}} + \frac{\mmlfirst{#1}}{\mmlsecond{#1}} } \else - \doifXMLvalelse {mfrac:linethickness} \mmlfraclinethickness { - \scratchdimen\XMLval{mfrac:linethickness}\mmlfraclinethickness{.4pt} + \doifXMLvalelse {mml:mfrac:linethickness} \mmlfraclinethickness { + \scratchdimen\XMLval{mml:mfrac:linethickness}\mmlfraclinethickness{.4pt} } { \setdimensionwithunit\scratchdimen\mmlfraclinethickness{pt} } { - {\xmlfirst{#1}} + {\mmlfirst{#1}} \above\scratchdimen {\mmlsecond{#1}} } @@ -2134,7 +1913,11 @@ \startxmlsetups mml:ms \hbox { \tf % else encoding problems + \edef\mmllquote{\xmlatt{#1}{lquote}} + \edef\mmlrquote{\xmlatt{#1}{rquote}} + \ifx\mmllquote\empty\symbol[leftquotation]\else\mmllquote\fi \applymmlsometext{#1}{\xmlflush{#1}} + \ifx\mmlrquote\empty\symbol[rightquotation]\else\mmlrquote\fi } \stopxmlsetups @@ -2166,19 +1949,42 @@ % mrow +% \startxmlsetups mml:mrow +% \begingroup +% \ifcase\xmlcount{#1}{/mml:mo}\relax +% \xmlflush{#1} +% \else % no \let +% \def\MMLleft {\left } +% \def\MMLright{\right} +% \enabledelimiter +% \checkdelimiters{\xmlall{#1}{/mml:mo}} +% \fakeleftdelimiter +% \xmlflush{#1} +% \fakerightdelimiter +% \disabledelimiter +% \fi +% \endgroup +% \stopxmlsetups + +% option: no fenced + \startxmlsetups mml:mrow \begingroup - \ifcase\xmlcount{#1}{/mml:mo}\relax - \xmlflush{#1} - \else % no \let - \def\MMLleft {\left } - \def\MMLright{\right} - \enabledelimiter - \checkdelimiters{\xmlall{#1}{/mml:mo}} - \fakeleftdelimiter + \ifnum\xmlcount{#1}{/mml:mo}=\plustwo + \xmldoifelse {#1} {/mml:mo[position()==1 or position()==\xmlcount{#1}{/*}]} {% we need a {} + \def\MMLleft {\left } + \def\MMLright{\right} + \enabledelimiter + \checkdelimiters{\xmlall{#1}{/mml:mo}} + \fakeleftdelimiter + \xmlflush{#1} + \fakerightdelimiter + \disabledelimiter + } { + \xmlflush{#1} + } + \else \xmlflush{#1} - \fakerightdelimiter - \disabledelimiter \fi \endgroup \stopxmlsetups @@ -2188,13 +1994,13 @@ \stopxmlsetups \startxmlsetups mml:mroot - \root{\mmlfirst{#1}}\of{\mmlsecond{#1}} + \root{\mmlsecond{#1}}\of{\mmlfirst{#1}} \stopxmlsetups \setupMMLappearance[scripts][\c!alternative=\v!a] % {} rond base \startxmlsetups mml:msub - \doifelse\@@MMLscriptsalternative\v!a { + \doifelse\MMLscriptsalternative\v!a { {\mmlfirst{#1}}_{\mmlsecond{#1}} } { \mmlfirst{#1} _{\mmlsecond{#1}} @@ -2202,7 +2008,7 @@ \stopxmlsetups \startxmlsetups mml:msup - \doifelse\@@MMLscriptsalternative\v!a { + \doifelse\MMLscriptsalternative\v!a { {\mmlfirst{#1}}^{\mmlsecond{#1}} } { \mmlfirst{#1} ^{\mmlsecond{#1}} @@ -2210,7 +2016,7 @@ \stopxmlsetups \startxmlsetups mml:msubsup - \doifelse\@@MMLscriptsalternative\v!a { + \doifelse\MMLscriptsalternative\v!a { {\mmlfirst{#1}}_{\mmlsecond{#1}}^{\mmlthird{#1}} } { \mmlfirst{#1} _{\mmlsecond{#1}}^{\mmlthird{#1}} @@ -2266,7 +2072,7 @@ % tables (mml:mtable, mml:mtr, mml:mlabledtr, mml:mtd) \startxmlsetups mml:mtable % some more attributes need to be supported - \ctxlua{lxml.mml.mtable("#1")} + \vcenter{\ctxlua{lxml.mml.mtable("#1")}} \stopxmlsetups \startxmlsetups mml:mspace % complete @@ -2290,8 +2096,8 @@ \startxmlsetups mml:mglyph % probably never ok \begingroup \edef\mmlglyphfontfamily{\xmlatt {#1}{fontfamily}} - \edef\mmlglyphalt {\xmlattdef{#1}{fontfamily}{unknown}} - \edef\mmlglyphindex {\xmlatt {#1}{fontfamily}} + \edef\mmlglyphalt {\xmlattdef{#1}{alt}{unknown}} + \edef\mmlglyphindex {\xmlatt {#1}{index}} \ifx \mmlglyphfontfamily \empty \hbox{\tttf[no fontfamily specified for \mmlglyphalt]} \else\ifx\mmlglyphindex\empty @@ -2350,8 +2156,8 @@ % </apply> % </apply> -\startxmlsetups mmc:minus - \doif \@@MMLsignreduction \v!yes { +\startxmlsetups mml:minus + \doif \MMLsignreduction \v!yes { \setMMLcreset{fn,\MMLcfunctionlist} } \ifcase\XMLstacklevel diff --git a/tex/context/base/x-mmp.mkiv b/tex/context/base/x-mmp.mkiv index 1b5dd97b3..dff7ade58 100644 --- a/tex/context/base/x-mmp.mkiv +++ b/tex/context/base/x-mmp.mkiv @@ -46,60 +46,61 @@ [" "] = "", } local i_replacements = { - ["sin"] = "\\mmlnolim{sin}", - ["cos"] = "\\mmlnolim{cos}", - ["abs"] = "\\mmlnolim{abs}", - ["arg"] = "\\mmlnolim{arg}", - ["codomain"] = "\\mmlnolim{codomain}", - ["curl"] = "\\mmlnolim{curl}", - ["determinant"] = "\\mmlnolim{det}", - ["divergence"] = "\\mmlnolim{div}", - ["domain"] = "\\mmlnolim{domain}", - ["false"] = "\\mmlnolim{false}", - ["gcd"] = "\\mmlnolim{gcd}", - ["grad"] = "\\mmlnolim{grad}", - ["identity"] = "\\mmlnolim{id}", - ["image"] = "\\mmlnolim{image}", - ["lcm"] = "\\mmlnolim{lcm}", - ["max"] = "\\mmlnolim{max}", - ["median"] = "\\mmlnolim{median}", - ["min"] = "\\mmlnolim{min}", - ["mode"] = "\\mmlnolim{mode}", - ["mod"] = "\\mmlnolim{mod}", - ["notanumber"] = "\\mmlnolim{NaN}", - ["otherwise"] = "\\mmlnolim{otherwise}", - ["true"] = "\\mmlnolim{true}", - ["declare"] = "\\mmlnolim{declare}", - ["as"] = "\\mmlnolim{as}", - ["polar"] = "\\mmlnolim{Polar}", - ["exp"] = "\\mmlnolim{exp}", - ["ln"] = "\\mmlnolim{ln}", - ["log"] = "\\mmlnolim{log}", - ["sin"] = "\\mmlnolim{sin}", - ["arcsin"] = "\\mmlnolim{arcsin}", - ["sinh"] = "\\mmlnolim{sinh}", - ["arcsinh"] = "\\mmlnolim{arcsinh}", - ["cos"] = "\\mmlnolim{cos}", - ["arccos"] = "\\mmlnolim{arccos}", - ["cosh"] = "\\mmlnolim{cosh}", - ["arccosh"] = "\\mmlnolim{arccosh}", - ["tan"] = "\\mmlnolim{tan}", - ["arctan"] = "\\mmlnolim{arctan}", - ["tanh"] = "\\mmlnolim{tanh}", - ["arctanh"] = "\\mmlnolim{arctanh}", - ["cot"] = "\\mmlnolim{cot}", - ["arccot"] = "\\mmlnolim{arccot}", - ["coth"] = "\\mmlnolim{coth}", - ["arccoth"] = "\\mmlnolim{arccoth}", - ["csc"] = "\\mmlnolim{csc}", - ["arccsc"] = "\\mmlnolim{arccsc}", - ["csch"] = "\\mmlnolim{csch}", - ["arccsch"] = "\\mmlnolim{arccsch}", - ["sec"] = "\\mmlnolim{sec}", - ["arcsec"] = "\\mmlnolim{arcsec}", - ["sech"] = "\\mmlnolim{sech}", - ["arcsech"] = "\\mmlnolim{arcsech}", + ["sin"] = "\\mathopnolimits{sin}", + ["cos"] = "\\mathopnolimits{cos}", + ["abs"] = "\\mathopnolimits{abs}", + ["arg"] = "\\mathopnolimits{arg}", + ["codomain"] = "\\mathopnolimits{codomain}", + ["curl"] = "\\mathopnolimits{curl}", + ["determinant"] = "\\mathopnolimits{det}", + ["divergence"] = "\\mathopnolimits{div}", + ["domain"] = "\\mathopnolimits{domain}", + ["gcd"] = "\\mathopnolimits{gcd}", + ["grad"] = "\\mathopnolimits{grad}", + ["identity"] = "\\mathopnolimits{id}", + ["image"] = "\\mathopnolimits{image}", + ["lcm"] = "\\mathopnolimits{lcm}", + ["max"] = "\\mathopnolimits{max}", + ["median"] = "\\mathopnolimits{median}", + ["min"] = "\\mathopnolimits{min}", + ["mode"] = "\\mathopnolimits{mode}", + ["mod"] = "\\mathopnolimits{mod}", + ["polar"] = "\\mathopnolimits{Polar}", + ["exp"] = "\\mathopnolimits{exp}", + ["ln"] = "\\mathopnolimits{ln}", + ["log"] = "\\mathopnolimits{log}", + ["sin"] = "\\mathopnolimits{sin}", + ["arcsin"] = "\\mathopnolimits{arcsin}", + ["sinh"] = "\\mathopnolimits{sinh}", + ["arcsinh"] = "\\mathopnolimits{arcsinh}", + ["cos"] = "\\mathopnolimits{cos}", + ["arccos"] = "\\mathopnolimits{arccos}", + ["cosh"] = "\\mathopnolimits{cosh}", + ["arccosh"] = "\\mathopnolimits{arccosh}", + ["tan"] = "\\mathopnolimits{tan}", + ["arctan"] = "\\mathopnolimits{arctan}", + ["tanh"] = "\\mathopnolimits{tanh}", + ["arctanh"] = "\\mathopnolimits{arctanh}", + ["cot"] = "\\mathopnolimits{cot}", + ["arccot"] = "\\mathopnolimits{arccot}", + ["coth"] = "\\mathopnolimits{coth}", + ["arccoth"] = "\\mathopnolimits{arccoth}", + ["csc"] = "\\mathopnolimits{csc}", + ["arccsc"] = "\\mathopnolimits{arccsc}", + ["csch"] = "\\mathopnolimits{csch}", + ["arccsch"] = "\\mathopnolimits{arccsch}", + ["sec"] = "\\mathopnolimits{sec}", + ["arcsec"] = "\\mathopnolimits{arcsec}", + ["sech"] = "\\mathopnolimits{sech}", + ["arcsech"] = "\\mathopnolimits{arcsech}", [" "] = "", + + ["false"] = "{\\mr false}", + ["notanumber"] = "{\\mr NaN}", + ["otherwise"] = "{\\mr otherwise}", + ["true"] = "{\\mr true}", + ["declare"] = "{\\mr declare}", + ["as"] = "{\\mr as}", } function lxml.mml.prepare_number(id,pattern) diff --git a/tex/context/interface/keys-cz.xml b/tex/context/interface/keys-cz.xml index 70473fe3b..0cc095221 100644 --- a/tex/context/interface/keys-cz.xml +++ b/tex/context/interface/keys-cz.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> -<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="cz" version="2008.05.13 14:42"> +<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="cz" version="2008.05.21 15:21"> <cd:variables> <cd:variable name="lesshyphenation" value="lesshyphenation"/> diff --git a/tex/context/interface/keys-de.xml b/tex/context/interface/keys-de.xml index 430b09aab..26c687b0b 100644 --- a/tex/context/interface/keys-de.xml +++ b/tex/context/interface/keys-de.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> -<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="de" version="2008.05.13 14:42"> +<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="de" version="2008.05.21 15:21"> <cd:variables> <cd:variable name="lesshyphenation" value="lesshyphenation"/> diff --git a/tex/context/interface/keys-en.xml b/tex/context/interface/keys-en.xml index d9b93f10d..b627027a9 100644 --- a/tex/context/interface/keys-en.xml +++ b/tex/context/interface/keys-en.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> -<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="en" version="2008.05.13 14:42"> +<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="en" version="2008.05.21 15:21"> <cd:variables> <cd:variable name="lesshyphenation" value="lesshyphenation"/> diff --git a/tex/context/interface/keys-fr.xml b/tex/context/interface/keys-fr.xml index 320cd677b..be8429449 100644 --- a/tex/context/interface/keys-fr.xml +++ b/tex/context/interface/keys-fr.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> -<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="fr" version="2008.05.13 14:42"> +<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="fr" version="2008.05.21 15:21"> <cd:variables> <cd:variable name="lesshyphenation" value="lesshyphenation"/> diff --git a/tex/context/interface/keys-it.xml b/tex/context/interface/keys-it.xml index 4e929bd87..0f0fbbd51 100644 --- a/tex/context/interface/keys-it.xml +++ b/tex/context/interface/keys-it.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> -<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="it" version="2008.05.13 14:42"> +<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="it" version="2008.05.21 15:21"> <cd:variables> <cd:variable name="lesshyphenation" value="lesshyphenation"/> diff --git a/tex/context/interface/keys-nl.xml b/tex/context/interface/keys-nl.xml index 0986c4f3b..437059374 100644 --- a/tex/context/interface/keys-nl.xml +++ b/tex/context/interface/keys-nl.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> -<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="nl" version="2008.05.13 14:42"> +<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="nl" version="2008.05.21 15:21"> <cd:variables> <cd:variable name="lesshyphenation" value="lesshyphenation"/> diff --git a/tex/context/interface/keys-ro.xml b/tex/context/interface/keys-ro.xml index 10c9d75d0..8ef0f6158 100644 --- a/tex/context/interface/keys-ro.xml +++ b/tex/context/interface/keys-ro.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> -<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="ro" version="2008.05.13 14:42"> +<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="ro" version="2008.05.21 15:21"> <cd:variables> <cd:variable name="lesshyphenation" value="lesshyphenation"/> diff --git a/web2c/contextcnf.lua b/web2c/contextcnf.lua new file mode 100644 index 000000000..d2708a925 --- /dev/null +++ b/web2c/contextcnf.lua @@ -0,0 +1,36 @@ +-- filename : texmfcnf.lua +-- comment : companion to luatex/mkiv +-- authors : Hans Hagen & Taco Hoekwater +-- copyright: not relevant +-- license : not relevant + +-- This file is read bij luatools, mtxrun and context mkiv. This is still +-- somewhat experimental and eventually we will support booleans instead +-- of the 't' strings. The content is similar to that of texmf.cnf. Both +-- namespaces strings +-- +-- TEXINPUT.context = "..." +-- +-- and subtables ( +-- +-- context = { TEXINPUT = ".." } +-- +-- are supported with the later a being the way to go. You can test settings +-- with: +-- +-- luatools --expand-var TEXMFBOGUS +-- +-- which should return +-- +-- It works! +-- +-- We first read the lua configuration file(s) and then do a first variable +-- expansion pass. Next we read the regular cnf files. These are cached +-- in the mkiv cache for faster loading. The lua configuration files are +-- not cached. + +return { +-- PURGECACHE = 't', -- this saves disk space +-- TEXMFCACHE = 'c:/temp', -- installers can change this + TEXMFBOGUS = 'It works!', -- a test string +} |