diff options
author | Hans Hagen <pragma@wxs.nl> | 2008-08-04 15:59:00 +0200 |
---|---|---|
committer | Hans Hagen <pragma@wxs.nl> | 2008-08-04 15:59:00 +0200 |
commit | f8ba0550d77fd6e2b307ff9dd3175fc0c613b8e2 (patch) | |
tree | ae27ca6edd0b2f1bcbe315d241b8152107d4e6a3 /scripts | |
parent | 1d63a6eae86a6b78d4563ed60521449e4bf89f3c (diff) | |
download | context-f8ba0550d77fd6e2b307ff9dd3175fc0c613b8e2.tar.gz |
stable 2008.08.04 15:59
Diffstat (limited to 'scripts')
65 files changed, 4849 insertions, 11639 deletions
diff --git a/scripts/context/lua/luatools.lua b/scripts/context/lua/luatools.lua index 89e5e0eb4..936b32e7b 100644 --- a/scripts/context/lua/luatools.lua +++ b/scripts/context/lua/luatools.lua @@ -3,12 +3,14 @@ -- one can make a stub: -- -- #!/bin/sh --- env LUATEXDIR=/....../texmf/scripts/context/lua luatex --luaonly=luatools.lua "$@" +-- env LUATEXDIR=/....../texmf/scripts/context/lua texlua luatools.lua "$@" + -- filename : luatools.lua -- comment : companion to context.tex -- author : Hans Hagen, PRAGMA-ADE, Hasselt NL -- copyright: PRAGMA ADE / ConTeXt Development Team -- license : see context related readme files + -- Although this script is part of the ConTeXt distribution it is -- relatively indepent of ConTeXt. The same is true for some of -- the luat files. We may may make them even less dependent in @@ -111,7 +113,7 @@ end function string:splitchr(chr) if #self > 0 then local t = { } - for s in string.gmatch(self..chr,"(.-)"..chr) do + for s in (self..chr):gmatch("(.-)"..chr) do t[#t+1] = s end return t @@ -120,22 +122,6 @@ function string:splitchr(chr) end end ---~ function string.piecewise(str, pat, fnc) -- variant of split ---~ local fpat = "(.-)"..pat ---~ local last_end = 1 ---~ local s, e, cap = string.find(str, fpat, 1) ---~ while s ~= nil do ---~ if s~=1 or cap~="" then ---~ fnc(cap) ---~ end ---~ last_end = e+1 ---~ s, e, cap = string.find(str, fpat, last_end) ---~ end ---~ if last_end <= #str then ---~ fnc((string.sub(str,last_end))) ---~ end ---~ end - function string.piecewise(str, pat, fnc) -- variant of split for k in string.splitter(str,pat) do fnc(k) end end @@ -654,35 +640,283 @@ function table.starts_at(t) return ipairs(t,1)(t,0) end -do +--~ do + +--~ -- one of my first exercises in lua ... + +--~ table.serialize_functions = true +--~ table.serialize_compact = true +--~ table.serialize_inline = true + +--~ local function key(k,noquotes) +--~ if type(k) == "number" then -- or k:find("^%d+$") then +--~ return "["..k.."]" +--~ elseif noquotes and k:find("^%a[%a%d%_]*$") then +--~ return k +--~ else +--~ return '["'..k..'"]' +--~ end +--~ end + +--~ local function simple_table(t) +--~ if #t > 0 then +--~ local n = 0 +--~ for _,v in pairs(t) do +--~ n = n + 1 +--~ end +--~ if n == #t then +--~ local tt = { } +--~ for i=1,#t do +--~ local v = t[i] +--~ local tv = type(v) +--~ if tv == "number" or tv == "boolean" then +--~ tt[#tt+1] = tostring(v) +--~ elseif tv == "string" then +--~ tt[#tt+1] = ("%q"):format(v) +--~ else +--~ tt = nil +--~ break +--~ end +--~ end +--~ return tt +--~ end +--~ end +--~ return nil +--~ end + +--~ local function serialize(root,name,handle,depth,level,reduce,noquotes,indexed) +--~ handle = handle or print +--~ reduce = reduce or false +--~ if depth then +--~ depth = depth .. " " +--~ if indexed then +--~ handle(("%s{"):format(depth)) +--~ else +--~ handle(("%s%s={"):format(depth,key(name,noquotes))) +--~ end +--~ else +--~ depth = "" +--~ local tname = type(name) +--~ if tname == "string" then +--~ if name == "return" then +--~ handle("return {") +--~ else +--~ handle(name .. "={") +--~ end +--~ elseif tname == "number" then +--~ handle("[" .. name .. "]={") +--~ elseif tname == "boolean" then +--~ if name then +--~ handle("return {") +--~ else +--~ handle("{") +--~ end +--~ else +--~ handle("t={") +--~ end +--~ end +--~ if root and next(root) then +--~ local compact = table.serialize_compact +--~ local inline = compact and table.serialize_inline +--~ local first, last = nil, 0 -- #root cannot be trusted here +--~ if compact then +--~ for k,v in ipairs(root) do -- NOT: for k=1,#root do (we need to quit at nil) +--~ if not first then first = k end +--~ last = last + 1 +--~ end +--~ end +--~ for _,k in pairs(table.sortedkeys(root)) do +--~ local v = root[k] +--~ local t = type(v) +--~ if compact and first and type(k) == "number" and k >= first and k <= last then +--~ if t == "number" then +--~ handle(("%s %s,"):format(depth,v)) +--~ elseif t == "string" then +--~ if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then +--~ handle(("%s %s,"):format(depth,v)) +--~ else +--~ handle(("%s %q,"):format(depth,v)) +--~ end +--~ elseif t == "table" then +--~ if not next(v) then +--~ handle(("%s {},"):format(depth)) +--~ elseif inline then +--~ local st = simple_table(v) +--~ if st then +--~ handle(("%s { %s },"):format(depth,table.concat(st,", "))) +--~ else +--~ serialize(v,k,handle,depth,level+1,reduce,noquotes,true) +--~ end +--~ else +--~ serialize(v,k,handle,depth,level+1,reduce,noquotes,true) +--~ end +--~ elseif t == "boolean" then +--~ handle(("%s %s,"):format(depth,tostring(v))) +--~ elseif t == "function" then +--~ if table.serialize_functions then +--~ handle(('%s loadstring(%q),'):format(depth,string.dump(v))) +--~ else +--~ handle(('%s "function",'):format(depth)) +--~ end +--~ else +--~ handle(("%s %q,"):format(depth,tostring(v))) +--~ end +--~ elseif k == "__p__" then -- parent +--~ if false then +--~ handle(("%s __p__=nil,"):format(depth)) +--~ end +--~ elseif t == "number" then +--~ handle(("%s %s=%s,"):format(depth,key(k,noquotes),v)) +--~ elseif t == "string" then +--~ if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then +--~ handle(("%s %s=%s,"):format(depth,key(k,noquotes),v)) +--~ else +--~ handle(("%s %s=%q,"):format(depth,key(k,noquotes),v)) +--~ end +--~ elseif t == "table" then +--~ if not next(v) then +--~ handle(("%s %s={},"):format(depth,key(k,noquotes))) +--~ elseif inline then +--~ local st = simple_table(v) +--~ if st then +--~ handle(("%s %s={ %s },"):format(depth,key(k,noquotes),table.concat(st,", "))) +--~ else +--~ serialize(v,k,handle,depth,level+1,reduce,noquotes) +--~ end +--~ else +--~ serialize(v,k,handle,depth,level+1,reduce,noquotes) +--~ end +--~ elseif t == "boolean" then +--~ handle(("%s %s=%s,"):format(depth,key(k,noquotes),tostring(v))) +--~ elseif t == "function" then +--~ if table.serialize_functions then +--~ handle(('%s %s=loadstring(%q),'):format(depth,key(k,noquotes),string.dump(v))) +--~ else +--~ handle(('%s %s="function",'):format(depth,key(k,noquotes))) +--~ end +--~ else +--~ handle(("%s %s=%q,"):format(depth,key(k,noquotes),tostring(v))) +--~ -- handle(('%s %s=loadstring(%q),'):format(depth,key(k,noquotes),string.dump(function() return v end))) +--~ end +--~ end +--~ if level > 0 then +--~ handle(("%s},"):format(depth)) +--~ else +--~ handle(("%s}"):format(depth)) +--~ end +--~ else +--~ handle(("%s}"):format(depth)) +--~ end +--~ end + +--~ --~ name: +--~ --~ +--~ --~ true : return { } +--~ --~ false : { } +--~ --~ nil : t = { } +--~ --~ string : string = { } +--~ --~ 'return' : return { } +--~ --~ number : [number] = { } + +--~ function table.serialize(root,name,reduce,noquotes) +--~ local t = { } +--~ local function flush(s) +--~ t[#t+1] = s +--~ end +--~ serialize(root, name, flush, nil, 0, reduce, noquotes) +--~ return table.concat(t,"\n") +--~ end + +--~ function table.tohandle(handle,root,name,reduce,noquotes) +--~ serialize(root, name, handle, nil, 0, reduce, noquotes) +--~ end + +--~ -- sometimes tables are real use (zapfino extra pro is some 85M) in which +--~ -- case a stepwise serialization is nice; actually, we could consider: +--~ -- +--~ -- for line in table.serializer(root,name,reduce,noquotes) do +--~ -- ...(line) +--~ -- end +--~ -- +--~ -- so this is on the todo list + +--~ table.tofile_maxtab = 2*1024 + +--~ function table.tofile(filename,root,name,reduce,noquotes) +--~ local f = io.open(filename,'w') +--~ if f then +--~ local concat = table.concat +--~ local maxtab = table.tofile_maxtab +--~ if maxtab > 1 then +--~ local t = { } +--~ local function flush(s) +--~ t[#t+1] = s +--~ if #t > maxtab then +--~ f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice +--~ t = { } +--~ end +--~ end +--~ serialize(root, name, flush, nil, 0, reduce, noquotes) +--~ f:write(concat(t,"\n"),"\n") +--~ else +--~ local function flush(s) +--~ f:write(s,"\n") +--~ end +--~ serialize(root, name, flush, nil, 0, reduce, noquotes) +--~ end +--~ f:close() +--~ end +--~ end + +--~ end + +--~ t = { +--~ b = "123", +--~ a = "x", +--~ c = 1.23, +--~ d = "1.23", +--~ e = true, +--~ f = { +--~ d = "1.23", +--~ a = "x", +--~ b = "123", +--~ c = 1.23, +--~ e = true, +--~ f = { +--~ e = true, +--~ f = { +--~ e = true +--~ }, +--~ }, +--~ }, +--~ g = function() end +--~ } + +--~ print(table.serialize(t), "\n") +--~ print(table.serialize(t,"name"), "\n") +--~ print(table.serialize(t,false), "\n") +--~ print(table.serialize(t,true), "\n") +--~ print(table.serialize(t,"name",true), "\n") +--~ print(table.serialize(t,"name",true,true), "\n") - -- one of my first exercises in lua ... - - -- 34.055.092 32.403.326 arabtype.tma - -- 1.620.614 1.513.863 lmroman10-italic.tma - -- 1.325.585 1.233.044 lmroman10-regular.tma - -- 1.248.157 1.158.903 lmsans10-regular.tma - -- 194.646 153.120 lmtypewriter10-regular.tma - -- 1.771.678 1.658.461 palatinosanscom-bold.tma - -- 1.695.251 1.584.491 palatinosanscom-regular.tma - -- 13.736.534 13.409.446 zapfinoextraltpro.tma - - -- 13.679.038 11.774.106 arabtype.tmc - -- 886.248 754.944 lmroman10-italic.tmc - -- 729.828 466.864 lmroman10-regular.tmc - -- 688.482 441.962 lmsans10-regular.tmc - -- 128.685 95.853 lmtypewriter10-regular.tmc - -- 715.929 582.985 palatinosanscom-bold.tmc - -- 669.942 540.126 palatinosanscom-regular.tmc - -- 1.560.588 1.317.000 zapfinoextraltpro.tmc +do table.serialize_functions = true table.serialize_compact = true table.serialize_inline = true + local sortedkeys = table.sortedkeys + local format, concat = string.format, table.concat + local noquotes, hexify, handle, reduce, compact, inline, functions + local pairs, ipairs, type, next, tostring = pairs, ipairs, type, next, tostring + local function key(k) if type(k) == "number" then -- or k:find("^%d+$") then - return "["..k.."]" + if hexify then + return ("[0x%04X]"):format(k) + else + return "["..k.."]" + end elseif noquotes and k:find("^%a[%a%d%_]*$") then return k else @@ -701,7 +935,13 @@ do for i=1,#t do local v = t[i] local tv = type(v) - if tv == "number" or tv == "boolean" then + if tv == "number" then + if hexify then + tt[#tt+1] = ("0x%04X"):format(v) + else + tt[#tt+1] = tostring(v) + end + elseif tv == "boolean" then tt[#tt+1] = tostring(v) elseif tv == "string" then tt[#tt+1] = ("%q"):format(v) @@ -716,53 +956,38 @@ do return nil end - local function serialize(root,name,handle,depth,level,reduce,noquotes,indexed) - handle = handle or print - reduce = reduce or false - if depth then + local function do_serialize(root,name,depth,level,indexed) + if level > 0 then depth = depth .. " " if indexed then handle(("%s{"):format(depth)) - else + elseif name then handle(("%s%s={"):format(depth,key(name))) - end - else - depth = "" - local tname = type(name) - if tname == "string" then - if name == "return" then - handle("return {") - else - handle(name .. "={") - end - elseif tname == "number" then - handle("[" .. name .. "]={") - elseif tname == "boolean" then - if name then - handle("return {") - else - handle("{") - end else - handle("t={") + handle(("%s{"):format(depth)) end end if root and next(root) then - local compact = table.serialize_compact - local inline = compact and table.serialize_inline local first, last = nil, 0 -- #root cannot be trusted here if compact then - for k,v in ipairs(root) do -- NOT: for k=1,#root do (why) + for k,v in ipairs(root) do -- NOT: for k=1,#root do (we need to quit at nil) if not first then first = k end last = last + 1 end end - for _,k in pairs(table.sortedkeys(root)) do + --~ for _,k in pairs(sortedkeys(root)) do -- 1% faster: + local sk = sortedkeys(root) + for i=1,#sk do + local k = sk[i] local v = root[k] local t = type(v) if compact and first and type(k) == "number" and k >= first and k <= last then if t == "number" then - handle(("%s %s,"):format(depth,v)) + if hexify then + handle(("%s 0x%04X,"):format(depth,v)) + else + handle(("%s %s,"):format(depth,v)) + end elseif t == "string" then if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then handle(("%s %s,"):format(depth,v)) @@ -775,17 +1000,17 @@ do elseif inline then local st = simple_table(v) if st then - handle(("%s { %s },"):format(depth,table.concat(st,", "))) + handle(("%s { %s },"):format(depth,concat(st,", "))) else - serialize(v,k,handle,depth,level+1,reduce,noquotes,true) + do_serialize(v,k,depth,level+1,true) end else - serialize(v,k,handle,depth,level+1,reduce,noquotes,true) + do_serialize(v,k,depth,level+1,true) end elseif t == "boolean" then handle(("%s %s,"):format(depth,tostring(v))) elseif t == "function" then - if table.serialize_functions then + if functions then handle(('%s loadstring(%q),'):format(depth,string.dump(v))) else handle(('%s "function",'):format(depth)) @@ -798,7 +1023,11 @@ do handle(("%s __p__=nil,"):format(depth)) end elseif t == "number" then - handle(("%s %s=%s,"):format(depth,key(k),v)) + if hexify then + handle(("%s %s=0x%04X,"):format(depth,key(k),v)) + else + handle(("%s %s=%s,"):format(depth,key(k),v)) + end elseif t == "string" then if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then handle(("%s %s=%s,"):format(depth,key(k),v)) @@ -811,17 +1040,17 @@ do elseif inline then local st = simple_table(v) if st then - handle(("%s %s={ %s },"):format(depth,key(k),table.concat(st,", "))) + handle(("%s %s={ %s },"):format(depth,key(k),concat(st,", "))) else - serialize(v,k,handle,depth,level+1,reduce,noquotes) + do_serialize(v,k,depth,level+1) end else - serialize(v,k,handle,depth,level+1,reduce,noquotes) + do_serialize(v,k,depth,level+1) end elseif t == "boolean" then handle(("%s %s=%s,"):format(depth,key(k),tostring(v))) elseif t == "function" then - if table.serialize_functions then + if functions then handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(v))) else handle(('%s %s="function",'):format(depth,key(k))) @@ -831,14 +1060,46 @@ do -- handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(function() return v end))) end end - if level > 0 then - handle(("%s},"):format(depth)) + end + if level > 0 then + handle(("%s},"):format(depth)) + end + end + + local function serialize(root,name,_handle,_reduce,_noquotes,_hexify) + noquotes = _noquotes + hexify = _hexify + handle = _handle or print + reduce = _reduce or false + compact = table.serialize_compact + inline = compact and table.serialize_inline + functions = table.serialize_functions + local tname = type(name) + if tname == "string" then + if name == "return" then + handle("return {") + else + handle(name .. "={") + end + elseif tname == "number" then + if hexify then + handle(format("[0x%04X]={",name)) else - handle(("%s}"):format(depth)) + handle("[" .. name .. "]={") + end + elseif tname == "boolean" then + if name then + handle("return {") + else + handle("{") end else - handle(("%s}"):format(depth)) + handle("t={") end + if root and next(root) then + do_serialize(root,name,"",0,indexed) + end + handle("}") end --~ name: @@ -850,17 +1111,17 @@ do --~ 'return' : return { } --~ number : [number] = { } - function table.serialize(root,name,reduce,noquotes) + function table.serialize(root,name,reduce,noquotes,hexify) local t = { } local function flush(s) t[#t+1] = s end - serialize(root, name, flush, nil, 0, reduce, noquotes) - return table.concat(t,"\n") + serialize(root,name,flush,reduce,noquotes,hexify) + return concat(t,"\n") end - function table.tohandle(handle,root,name,reduce,noquotes) - serialize(root, name, handle, nil, 0, reduce, noquotes) + function table.tohandle(handle,root,name,reduce,noquotes,hexify) + serialize(root,name,handle,reduce,noquotes,hexify) end -- sometimes tables are real use (zapfino extra pro is some 85M) in which @@ -874,10 +1135,9 @@ do table.tofile_maxtab = 2*1024 - function table.tofile(filename,root,name,reduce,noquotes) + function table.tofile(filename,root,name,reduce,noquotes,hexify) local f = io.open(filename,'w') if f then - local concat = table.concat local maxtab = table.tofile_maxtab if maxtab > 1 then local t = { } @@ -888,13 +1148,13 @@ do t = { } end end - serialize(root, name, flush, nil, 0, reduce, noquotes) + serialize(root,name,flush,reduce,noquotes,hexify) f:write(concat(t,"\n"),"\n") else local function flush(s) f:write(s,"\n") end - serialize(root, name, flush, nil, 0, reduce, noquotes) + serialize(root,name,flush,reduce,noquotes,hexify) end f:close() end @@ -902,35 +1162,6 @@ do end ---~ t = { ---~ b = "123", ---~ a = "x", ---~ c = 1.23, ---~ d = "1.23", ---~ e = true, ---~ f = { ---~ d = "1.23", ---~ a = "x", ---~ b = "123", ---~ c = 1.23, ---~ e = true, ---~ f = { ---~ e = true, ---~ f = { ---~ e = true ---~ }, ---~ }, ---~ }, ---~ g = function() end ---~ } - ---~ print(table.serialize(t), "\n") ---~ print(table.serialize(t,"name"), "\n") ---~ print(table.serialize(t,false), "\n") ---~ print(table.serialize(t,true), "\n") ---~ print(table.serialize(t,"name",true), "\n") ---~ print(table.serialize(t,"name",true,true), "\n") - do local function flatten(t,f,complete) @@ -1121,7 +1352,7 @@ function io.loaddata(filename) end function io.savedata(filename,data,joiner) - local f = io.open(filename, "wb") + local f = io.open(filename,"wb") if f then if type(data) == "table" then f:write(table.join(data,joiner or "")) @@ -1131,6 +1362,9 @@ function io.savedata(filename,data,joiner) f:write(data) end f:close() + return true + else + return false end end @@ -1465,6 +1699,9 @@ end -- copyright: PRAGMA ADE / ConTeXt Development Team -- license : see context related readme files + +--~ print(table.serialize(os.uname())) + if not versions then versions = { } end versions['l-os'] = 1.001 function os.resultof(command) @@ -1561,9 +1798,11 @@ if not versions then versions = { } end versions['l-file'] = 1.001 if not file then file = { } end function file.removesuffix(filename) - return filename:gsub("%.[%a%d]+$", "") + return (filename:gsub("%.[%a%d]+$","")) end +file.stripsuffix = file.removesuffix + function file.addsuffix(filename, suffix) if not filename:find("%.[%a%d]+$") then return filename .. "." .. suffix @@ -1573,11 +1812,7 @@ function file.addsuffix(filename, suffix) end function file.replacesuffix(filename, suffix) - if not filename:find("%.[%a%d]+$") then - return filename .. "." .. suffix - else - return (filename:gsub("%.[%a%d]+$","."..suffix)) - end + return (filename:gsub("%.[%a%d]+$","")) .. "." .. suffix end function file.dirname(name) @@ -1598,10 +1833,6 @@ end file.suffix = file.extname -function file.stripsuffix(name) - return (name:gsub("%.[%a%d]+$","")) -end - --~ function file.join(...) --~ local t = { ... } --~ for i=1,#t do @@ -1650,6 +1881,16 @@ function file.is_readable(name) end end +function file.iswritable(name) + local a = lfs.attributes(name) + return a and a.permissions:sub(2,2) == "w" +end + +function file.isreadable(name) + local a = lfs.attributes(name) + return a and a.permissions:sub(1,1) == "r" +end + --~ function file.split_path(str) --~ if str:find(';') then --~ return str:splitchr(";") @@ -1677,34 +1918,26 @@ function file.join_path(tab) return table.concat(tab,io.pathseparator) -- can have trailing // end ---~ print('test' .. " == " .. file.collapse_path("test")) ---~ print("test/test" .. " == " .. file.collapse_path("test/test")) ---~ print("test/test/test" .. " == " .. file.collapse_path("test/test/test")) ---~ print("test/test" .. " == " .. file.collapse_path("test/../test/test")) ---~ print("test" .. " == " .. file.collapse_path("test/../test")) ---~ print("../test" .. " == " .. file.collapse_path("../test")) ---~ 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 n = 1 - while n > 0 do - str, n = str:gsub("([^/%.]+/%.%./)","") - end - return (str:gsub("/%./","/")) -end + str = str:gsub("/%./","/") + local n, m = 1, 1 + while n > 0 or m > 0 do + str, n = str:gsub("[^/%.]+/%.%.$","") + str, m = str:gsub("[^/%.]+/%.%./","") + end + str = str:gsub("([^/])/$","%1") + str = str:gsub("^%./","") + str = str:gsub("/%.$","") + if str == "" then str = "." end + return str +end + +--~ print(file.collapse_path("a/./b/..")) +--~ print(file.collapse_path("a/aa/../b/bb")) +--~ print(file.collapse_path("a/../..")) +--~ print(file.collapse_path("a/.././././b/..")) +--~ print(file.collapse_path("a/./././b/..")) +--~ print(file.collapse_path("a/b/c/../..")) function file.robustname(str) return (str:gsub("[^%a%d%/%-%.\\]+","-")) @@ -1717,6 +1950,98 @@ function file.copy(oldname,newname) file.savedata(newname,io.loaddata(oldname)) end +-- lpeg variants, slightly faster, not always + +--~ local period = lpeg.P(".") +--~ local slashes = lpeg.S("\\/") +--~ local noperiod = 1-period +--~ local noslashes = 1-slashes +--~ local name = noperiod^1 + +--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.C(noperiod^1) * -1 + +--~ function file.extname(name) +--~ return pattern:match(name) or "" +--~ end + +--~ local pattern = lpeg.Cs(((period * noperiod^1 * -1)/"" + 1)^1) + +--~ function file.removesuffix(name) +--~ return pattern:match(name) +--~ end + +--~ file.stripsuffix = file.removesuffix + +--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1 + +--~ function file.basename(name) +--~ return pattern:match(name) or name +--~ end + +--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.Cp() * noslashes^1 * -1 + +--~ function file.dirname(name) +--~ local p = pattern:match(name) +--~ if p then +--~ return name:sub(1,p-2) +--~ else +--~ return "" +--~ end +--~ end + +--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1 + +--~ function file.addsuffix(name, suffix) +--~ local p = pattern:match(name) +--~ if p then +--~ return name +--~ else +--~ return name .. "." .. suffix +--~ end +--~ end + +--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1 + +--~ function file.replacesuffix(name,suffix) +--~ local p = pattern:match(name) +--~ if p then +--~ return name:sub(1,p-2) .. "." .. suffix +--~ else +--~ return name .. "." .. suffix +--~ end +--~ end + +--~ local pattern = (noslashes^0 * slashes)^0 * lpeg.Cp() * ((noperiod^1 * period)^1 * lpeg.Cp() + lpeg.P(true)) * noperiod^1 * -1 + +--~ function file.nameonly(name) +--~ local a, b = pattern:match(name) +--~ if b then +--~ return name:sub(a,b-2) +--~ elseif a then +--~ return name:sub(a) +--~ else +--~ return name +--~ end +--~ end + +--~ local test = file.extname +--~ local test = file.stripsuffix +--~ local test = file.basename +--~ local test = file.dirname +--~ local test = file.addsuffix +--~ local test = file.replacesuffix +--~ local test = file.nameonly + +--~ print(1,test("./a/b/c/abd.def.xxx","!!!")) +--~ print(2,test("./../b/c/abd.def.xxx","!!!")) +--~ print(3,test("a/b/c/abd.def.xxx","!!!")) +--~ print(4,test("a/b/c/def.xxx","!!!")) +--~ print(5,test("a/b/c/def","!!!")) +--~ print(6,test("def","!!!")) +--~ print(7,test("def.xxx","!!!")) + +--~ local tim = os.clock() for i=1,250000 do local ext = test("abd.def.xxx","!!!") end print(os.clock()-tim) + -- filename : l-url.lua -- author : Hans Hagen, PRAGMA-ADE, Hasselt NL @@ -1837,51 +2162,6 @@ dir = { } if lfs then do ---~ local attributes = lfs.attributes ---~ local walkdir = lfs.dir ---~ ---~ local function glob_pattern(path,patt,recurse,action) ---~ local ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe ---~ if ok and type(scanner) == "function" then ---~ if not path:find("/$") then path = path .. '/' end ---~ for name in scanner do ---~ local full = path .. name ---~ local mode = attributes(full,'mode') ---~ if mode == 'file' then ---~ if name:find(patt) then ---~ action(full) ---~ end ---~ elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then ---~ glob_pattern(full,patt,recurse,action) ---~ end ---~ end ---~ end ---~ end ---~ ---~ dir.glob_pattern = glob_pattern ---~ ---~ local function glob(pattern, action) ---~ local t = { } ---~ local action = action or function(name) t[#t+1] = name end ---~ local path, patt = pattern:match("^(.*)/*%*%*/*(.-)$") ---~ local recurse = path and patt ---~ if not recurse then ---~ path, patt = pattern:match("^(.*)/(.-)$") ---~ if not (path and patt) then ---~ path, patt = '.', pattern ---~ end ---~ end ---~ patt = patt:gsub("([%.%-%+])", "%%%1") ---~ patt = patt:gsub("%*", ".*") ---~ patt = patt:gsub("%?", ".") ---~ patt = "^" .. patt .. "$" ---~ -- print('path: ' .. path .. ' | pattern: ' .. patt .. ' | recurse: ' .. tostring(recurse)) ---~ glob_pattern(path,patt,recurse,action) ---~ return t ---~ end ---~ ---~ dir.glob = glob - local attributes = lfs.attributes local walkdir = lfs.dir @@ -1959,13 +2239,17 @@ if lfs then do glob(s,t) end return t + elseif lfs.isfile(str) then + local t = t or { } + t[#t+1] = str + return t else local split = pattern:match(str) if split then local t = t or { } local action = action or function(name) t[#t+1] = name end local root, path, base = split[1], split[2], split[3] - local recurse = base:find("**") + local recurse = base:find("%*%*") local start = root .. path local result = filter:match(start .. base) glob_pattern(start,result,recurse,action) @@ -1993,16 +2277,21 @@ if lfs then do for name in walkdir(path) do if name:find("^%.") then --- skip - elseif attributes(name,'mode') == "directory" then - if recurse then - globfiles(path .. "/" .. name,recurse,func,files) - end - elseif func then - if func(name) then - files[#files+1] = path .. "/" .. name - end else - files[#files+1] = path .. "/" .. name + local mode = attributes(name,'mode') + if mode == "directory" then + if recurse then + globfiles(path .. "/" .. name,recurse,func,files) + end + elseif mode == "file" then + if func then + if func(name) then + files[#files+1] = path .. "/" .. name + end + else + files[#files+1] = path .. "/" .. name + end + end end end return files @@ -2210,7 +2499,7 @@ function toboolean(str,tolerant) if tolerant then local tstr = type(str) if tstr == "string" then - return str == "true" or str == "yes" or str == "on" or str == "1" + return str == "true" or str == "yes" or str == "on" or str == "1" or str == "t" elseif tstr == "number" then return tonumber(str) ~= 0 elseif tstr == "nil" then @@ -2229,9 +2518,9 @@ end function string.is_boolean(str) if type(str) == "string" then - if str == "true" or str == "yes" or str == "on" then + if str == "true" or str == "yes" or str == "on" or str == "t" then return true - elseif str == "false" or str == "no" or str == "off" then + elseif str == "false" or str == "no" or str == "off" or str == "f" then return false end end @@ -2301,8 +2590,8 @@ function unicode.utftype(f) -- \000 fails ! end end -function unicode.utf16_to_utf8(str, endian) - garbagecollector.push() +function unicode.utf16_to_utf8(str, endian) -- maybe a gsub is faster or an lpeg +--~ garbagecollector.push() local result = { } local tc, uc = table.concat, unicode.utf8.char local tmp, n, m, p = { }, 0, 0, 0 @@ -2324,30 +2613,32 @@ function unicode.utf16_to_utf8(str, endian) end end for l,r in str:bytepairs() do - if endian then - n = l*256 + r - else - n = r*256 + l - end - if m > 0 then - n = (m-0xD800)*0x400 + (n-0xDC00) + 0x10000 - m = 0 - doit() - elseif n >= 0xD800 and n <= 0xDBFF then - m = n - else - doit() + if r then + if endian then + n = l*256 + r + else + n = r*256 + l + end + if m > 0 then + n = (m-0xD800)*0x400 + (n-0xDC00) + 0x10000 + m = 0 + doit() + elseif n >= 0xD800 and n <= 0xDBFF then + m = n + else + doit() + end end end if #tmp > 0 then result[#result+1] = tc(tmp,"") end - garbagecollector.pop() +--~ garbagecollector.pop() return result end function unicode.utf32_to_utf8(str, endian) - garbagecollector.push() +--~ garbagecollector.push() local result = { } local tc, uc = table.concat, unicode.utf8.char local tmp, n, m, p = { }, 0, -1, 0 @@ -2392,10 +2683,36 @@ function unicode.utf32_to_utf8(str, endian) if #tmp > 0 then result[#result+1] = tc(tmp,"") end - garbagecollector.pop() +--~ garbagecollector.pop() return result end +function unicode.utf8_to_utf16(str,littleendian) + if littleendian then + return char(255,254) .. utf.gsub(str,".",function(c) + local b = byte(c) + if b < 0x10000 then + return char(b%256,b/256) + else + b = b - 0x10000 + local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00 + return char(b1%256,b1/256,b2%256,b2/256) + end + end) + else + return char(254,255) .. utf.gsub(str,".",function(c) + local b = byte(c) + if b < 0x10000 then + return char(b/256,b%256) + else + b = b - 0x10000 + local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00 + return char(b1/256,b1%256,b2/256,b2%256) + end + end) + end +end + -- filename : l-utils.lua -- comment : split off from luat-lib @@ -2429,12 +2746,18 @@ function utils.report(...) print(...) end +utils.merger.strip_comment = true + function utils.merger._self_load_(name) local f, data = io.open(name), "" if f then data = f:read("*all") f:close() end + if data and utils.merger.strip_comment then + -- saves some 20K + data = data:gsub("%-%-~[^\n\r]*[\r\n]", "") + end return data or "" end @@ -2512,108 +2835,62 @@ function utils.merger.selfclean(name) ) end -utils.lua.compile_strip = true - -function utils.lua.compile(luafile, lucfile) +function utils.lua.compile(luafile, lucfile, cleanup, strip) -- defaults: cleanup=false strip=true -- utils.report("compiling",luafile,"into",lucfile) os.remove(lucfile) local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile) - if utils.lua.compile_strip then + if strip ~= false 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 == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then + -- utils.report("removing",luafile) + os.remove(luafile) end + return done end --- filename : luat-lib.lua --- comment : companion to luat-lib.tex --- author : Hans Hagen, PRAGMA-ADE, Hasselt NL --- copyright: PRAGMA ADE / ConTeXt Development Team --- license : see context related readme files - -if not versions then versions = { } end versions['luat-lib'] = 1.001 - --- mostcode moved to the l-*.lua and other luat-*.lua files +if not modules then modules = { } end modules ['luat-lib'] = { + version = 1.001, + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", + comment = "companion to luat-lib.tex", +} --- os / io +-- most code already moved to the l-*.lua and other luat-*.lua files os.setlocale(nil,nil) -- useless feature and even dangerous in luatex --- os.platform - --- mswin|bccwin|mingw|cygwin windows --- darwin|rhapsody|nextstep macosx --- netbsd|unix unix --- linux linux - -if not io.fileseparator then - if string.find(os.getenv("PATH"),";") then - io.fileseparator, io.pathseparator, os.platform = "\\", ";", os.type or "windows" - else - io.fileseparator, io.pathseparator, os.platform = "/" , ":", os.type or "unix" - end -end - -os.platform = os.platform or os.type or (io.pathseparator == ";" and "windows") or "unix" - --- arg normalization --- --- for k,v in pairs(arg) do print(k,v) 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 +function os.setlocale() + -- no way you can mess with it 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 - -environment.platform = os.platform +environment = environment or { } +environment.arguments = { } +environment.files = { } +environment.sortedflags = nil function environment.initialize_arguments(arg) - environment.arguments = { } - environment.files = { } - environment.sorted_argument_keys = nil + local arguments, files = { }, { } + environment.arguments, environment.files, environment.sortedflags = arguments, files, nil for index, argument in pairs(arg) do if index > 0 then local flag, value = argument:match("^%-+(.+)=(.-)$") if flag then - environment.arguments[flag] = string.unquote(value or "") + arguments[flag] = string.unquote(value or "") else flag = argument:match("^%-+(.+)") if flag then - environment.arguments[flag] = true + arguments[flag] = true else - environment.files[#environment.files+1] = argument + files[#files+1] = argument end end end @@ -2635,18 +2912,20 @@ function environment.setargument(name,value) end function environment.argument(name) - if environment.arguments[name] then - return environment.arguments[name] + local arguments, sortedflags = environment.arguments, environment.sortedflags + if arguments[name] then + return arguments[name] else - if not environment.sorted_argument_keys then - environment.sorted_argument_keys = { } - for _,v in pairs(table.sortedkeys(environment.arguments)) do - table.insert(environment.sorted_argument_keys, "^" .. v) + if not sortedflags then + sortedflags = { } + for _,v in pairs(table.sortedkeys(arguments)) do + sortedflags[#sortedflags+1] = "^" .. v end + environment.sortedflags = sortedflags end - for _,v in pairs(environment.sorted_argument_keys) do + for _,v in ipairs(sortedflags) do if name:find(v) then - return environment.arguments[v:sub(2,#v)] + return arguments[v:sub(2,#v)] end end end @@ -2694,21 +2973,24 @@ if arg then end --- filename : luat-inp.lua --- comment : companion to luat-lib.tex --- author : Hans Hagen, PRAGMA-ADE, Hasselt NL --- copyright: PRAGMA ADE / ConTeXt Development Team --- license : see context related readme files - --- This lib is multi-purpose and can be loaded again later on so that --- additional functionality becomes available. We will split this --- module in components when we're done with prototyping. +if not modules then modules = { } end modules ['luat-inp'] = { + version = 1.001, + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", + comment = "companion to luat-lib.tex", +} -- 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. +-- This lib is multi-purpose and can be loaded again later on so that +-- additional functionality becomes available. We will split this +-- module in components once we're done with prototyping. This is the +-- first code I wrote for LuaTeX, so it needs some cleanup. Before changing +-- something in this module one can best check with Taco or Hans first; there +-- is some nasty trickery going on that relates to traditional kpse support. -- To be considered: hash key lowercase, first entry in table filename -- (any case), rest paths (so no need for optimization). Or maybe a @@ -2718,12 +3000,6 @@ end -- Beware, loading and saving is overloaded in luat-tmp! -if not versions then versions = { } end versions['luat-inp'] = 1.001 -if not environment then environment = { } end -if not file then file = { } end - -if environment.aleph_mode == nil then environment.aleph_mode = true end -- temp hack - if not input then input = { } end if not input.suffixes then input.suffixes = { } end if not input.formats then input.formats = { } end @@ -2749,8 +3025,16 @@ input.debug = false input.cnfname = 'texmf.cnf' input.luaname = 'texmfcnf.lua' input.lsrname = 'ls-R' -input.luasuffix = '.tma' -input.lucsuffix = '.tmc' +input.homedir = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~' + +--~ input.luasuffix = 'tma' +--~ input.lucsuffix = 'tmc' + +-- for the moment we have .local but this will disappear +input.cnfdefault = '{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}' + +-- chances are low that the cnf file is in the bin path +input.cnfdefault = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}' -- we use a cleaned up list / format=any is a wildcard, as is *name @@ -2786,7 +3070,8 @@ input.suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' } -- FONTFEATURES = .;$TEXMF/fonts/fea// -- FONTCIDMAPS = .;$TEXMF/fonts/cid// -function input.checkconfigdata(instance) -- not yet ok, no time for debugging now +function input.checkconfigdata() -- not yet ok, no time for debugging now + local instance = input.instance local function fix(varname,default) local proname = varname .. "." .. instance.progname or "crap" local p = instance.environment[proname] @@ -2795,7 +3080,15 @@ function input.checkconfigdata(instance) -- not yet ok, no time for debugging no instance.variables[varname] = default -- or environment? end end - fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") + local name = os.name + if name == "windows" then + fix("OSFONTDIR", "c:/windows/fonts//") + elseif name == "macosx" then + fix("OSFONTDIR", "$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//") + else + -- bad luck + end + fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") end @@ -2822,14 +3115,20 @@ input.formats ['sfd'] = 'SFDFONTS' input.suffixes ['sfd'] = { 'sfd' } input.alternatives['subfont definition files'] = 'sfd' -function input.reset() +-- In practice we will work within one tds tree, but i want to keep +-- the option open to build tools that look at multiple trees, which is +-- why we keep the tree specific data in a table. We used to pass the +-- instance but for practical pusposes we now avoid this and use a +-- instance variable. + +function input.newinstance() local instance = { } instance.rootpath = '' instance.treepath = '' - instance.progname = environment.progname or 'context' - instance.engine = environment.engine or 'luatex' + instance.progname = 'context' + instance.engine = 'luatex' instance.format = '' instance.environment = { } instance.variables = { } @@ -2853,12 +3152,12 @@ function input.reset() instance.cachepath = nil instance.loaderror = false instance.smallcache = false + instance.sortdata = false instance.savelists = true instance.cleanuppaths = true instance.allresults = false instance.pattern = nil -- lists instance.kpseonly = false -- lists - instance.cachefile = 'tmftools' instance.loadtime = 0 instance.starttime = 0 instance.stoptime = 0 @@ -2869,23 +3168,13 @@ function input.reset() instance.fakepaths = { } instance.lsrmode = false - if os.env then - -- store once, freeze and faster - for k,v in pairs(os.env) do - instance.environment[k] = input.bare_variable(v) - end - else - -- we will access os.env frequently - 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)) - instance.environment[v] = input.bare_variable(e) - end - end + -- store once, freeze and faster (once reset we can best use instance.environment) + + for k,v in pairs(os.env) do + instance.environment[k] = input.bare_variable(v) end - -- cross referencing + -- cross referencing, delayed because we can add suffixes for k, v in pairs(input.suffixes) do for _, vv in pairs(v) do @@ -2899,68 +3188,42 @@ function input.reset() end -function input.reset_hashes(instance) - instance.lists = { } - instance.found = { } -end - -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 +input.instance = input.instance or nil -if texio then - input.log = texio.write_nl -else - input.log = print +function input.reset() + input.instance = input.newinstance() + return input.instance end -function input.simple_logger(kind, name) - if name and name ~= "" then - if input.banner then - input.log(input.banner..kind..": "..name) - else - input.log("<<"..kind..": "..name..">>") - end - else - if input.banner then - input.log(input.banner..kind..": no name") - else - input.log("<<"..kind..": no name>>") - end - end +function input.reset_hashes() + input.instance.lists = { } + input.instance.found = { } end -function input.dummy_logger() +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 function input.settrace(n) input.trace = tonumber(n or 0) if input.trace > 0 then - input.logger = input.simple_logger input.verbose = true - else - input.logger = function() end end end -function input.report(...) -- inefficient +input.log = (texio and texio.write_nl) or print + +function input.report(...) if input.verbose then - if input.banner then - input.log(input.banner .. table.concat({...},' ')) - elseif input.logmode() == 'xml' then - input.log("<t>"..table.concat({...},' ').."</t>") - else - input.log("<<"..table.concat({...},' ')..">>") - end + input.log("<<"..format(...)..">>") end end -function input.reportlines(str) - if type(str) == "string" then - str = str:split("\n") +function input.report(...) + if input.trace > 0 then -- extra test + input.log("<<"..format(...)..">>") end - for _,v in pairs(str) do input.report(v) end end input.settrace(tonumber(os.getenv("MTX.INPUT.TRACE") or os.getenv("MTX_INPUT_TRACE") or input.trace or 0)) @@ -2989,7 +3252,7 @@ do instance.stoptime = stoptime instance.loadtime = instance.loadtime + loadtime if report then - input.report('load time', format("%0.3f",loadtime)) + input.report("load time %0.3f",loadtime) end return loadtime end @@ -3005,18 +3268,18 @@ end function input.report_loadtime(instance) if instance then - input.report('total load time', input.elapsedtime(instance)) + input.report('total load time %s', input.elapsedtime(instance)) end end input.loadtime = input.elapsedtime -function input.env(instance,key) - return instance.environment[key] or input.osenv(instance,key) +function input.env(key) + return input.instance.environment[key] or input.osenv(key) end -function input.osenv(instance,key) - local ie = instance.environment +function input.osenv(key) + local ie = input.instance.environment local value = ie[key] if value == nil then -- local e = os.getenv(key) @@ -3034,81 +3297,106 @@ end -- we follow a rather traditional approach: -- -- (1) texmf.cnf given in TEXMFCNF --- (2) texmf.cnf searched in TEXMF/web2c +-- (2) texmf.cnf searched in default variable -- --- for the moment we don't expect a configuration file in a zip +-- also we now follow the stupid route: if not set then just assume *one* +-- cnf file under texmf (i.e. distribution) -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 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 +input.ownpath = input.ownpath or nil +input.ownbin = input.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex" +input.autoselfdir = true -- false may be handy for debugging + +function input.getownpath() + if not input.ownpath then + if input.autoselfdir and os.selfdir then + input.ownpath = os.selfdir + else + local binary = input.ownbin + if os.platform == "windows" then + binary = file.replacesuffix(binary,"exe") + end + for p in string.gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do + local b = file.join(p,binary) + if lfs.isfile(b) then + -- we assume that after changing to the path the currentdir function + -- resolves to the real location and use this side effect here; this + -- trick is needed because on the mac installations use symlinks in the + -- path instead of real locations + local olddir = lfs.currentdir() + if lfs.chdir(p) then + local pp = lfs.currentdir() + if input.verbose and p ~= pp then + input.report("following symlink %s to %s",p,pp) 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 + input.ownpath = pp + lfs.chdir(olddir) + else + if input.verbose then + input.report("unable to check path %s",p) end + input.ownpath = p 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() + break 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 - else - local t = input.split_path(input.env(instance,'TEXMFCNF')) - t = input.aux.expanded_path(instance,t) - input.aux.expand_vars(instance,t) - 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 + if not input.ownpath then input.ownpath = '.' end + end + return input.ownpath +end + +function input.identify_own() + local instance = input.instance + local ownpath = input.getownpath() or lfs.currentdir() + local ie = instance.environment + if ownpath then + if input.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end + if input.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end + if input.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end + else + input.verbose = true + input.report("error: unable to locate ownpath") + os.exit() + end + if input.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = input.cnfdefault end + if input.env('TEXOS') == "" then os.env['TEXOS'] = input.env('SELFAUTODIR') end + if input.env('TEXROOT') == "" then os.env['TEXROOT'] = input.env('SELFAUTOPARENT') end + if input.verbose then + for _,v in ipairs({"SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF"}) do + input.report("variable %s set to %s",v,input.env(v) or "unknown") + end + end + function input.identify_own() end +end + +function input.identify_cnf() + local instance = input.instance + if #instance.cnffiles == 0 then + -- fallback + input.identify_own() + -- the real search + input.expand_variables() + local t = input.split_path(input.env('TEXMFCNF')) + t = input.aux.expanded_path(t) + input.aux.expand_vars(t) -- redundant + 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 - locate(input.luaname,instance.luafiles) - locate(input.cnfname,instance.cnffiles) end + locate(input.luaname,instance.luafiles) + locate(input.cnfname,instance.cnffiles) end end -function input.load_cnf(instance) +function input.load_cnf() + local instance = input.instance local function loadoldconfigdata() for _, fname in ipairs(instance.cnffiles) do - input.aux.load_cnf(instance,fname) + input.aux.load_cnf(fname) end end -- instance.cnffiles contain complete names now ! @@ -3123,27 +3411,27 @@ function input.load_cnf(instance) 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 loadoldconfigdata() elseif instance.diskcache and not instance.renewcache then - input.loadoldconfig(instance,instance.cnffiles) + input.loadoldconfig(instance.cnffiles) if instance.loaderror then loadoldconfigdata() - input.saveoldconfig(instance) + input.saveoldconfig() end else loadoldconfigdata() if instance.renewcache then - input.saveoldconfig(instance) + input.saveoldconfig() end end - input.aux.collapse_cnf_data(instance) + input.aux.collapse_cnf_data() end - input.checkconfigdata(instance) + input.checkconfigdata() end -function input.load_lua(instance) +function input.load_lua() + local instance = input.instance if #instance.luafiles == 0 then -- yet harmless else @@ -3155,14 +3443,14 @@ function input.load_lua(instance) 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) + input.loadnewconfig() + input.aux.collapse_cnf_data() end - input.checkconfigdata(instance) + input.checkconfigdata() end -function input.aux.collapse_cnf_data(instance) -- potential optmization: pass start index (setup and configuration are shared) +function input.aux.collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared) + local instance = input.instance for _,c in ipairs(instance.order) do for k,v in pairs(c) do if not instance.variables[k] then @@ -3177,21 +3465,22 @@ function input.aux.collapse_cnf_data(instance) -- potential optmization: pass st end end -function input.aux.load_cnf(instance,fname) +function input.aux.load_cnf(fname) + local instance = input.instance fname = input.clean_path(fname) - local lname = fname:gsub("%.%a+$",input.luasuffix) + local lname = file.replacesuffix(fname,'lua') local f = io.open(lname) if f then -- this will go f:close() local dname = file.dirname(fname) if not instance.configuration[dname] then - input.aux.load_configuration(instance,dname,lname) + input.aux.load_configuration(dname,lname) instance.order[#instance.order+1] = instance.configuration[dname] end else f = io.open(fname) if f then - input.report("loading", fname) + input.report("loading %s", fname) local line, data, n, k, v local dname = file.dirname(fname) if not instance.configuration[dname] then @@ -3223,227 +3512,226 @@ function input.aux.load_cnf(instance,fname) end f:close() else - input.report("skipping", fname) + input.report("skipping %s", fname) end end end -- database loading -function input.load_hash(instance) - input.locatelists(instance) +function input.load_hash() + local instance = input.instance + input.locatelists() if instance.lsrmode then - input.loadlists(instance) + input.loadlists() elseif instance.diskcache and not instance.renewcache then - input.loadfiles(instance) + input.loadfiles() if instance.loaderror then - input.loadlists(instance) - input.savefiles(instance) + input.loadlists() + input.savefiles() end else - input.loadlists(instance) + input.loadlists() if instance.renewcache then - input.savefiles(instance) + input.savefiles() end end end -function input.aux.append_hash(instance,type,tag,name) - input.logger("= hash append",tag) - table.insert(instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } ) +function input.aux.append_hash(type,tag,name) + if input.trace > 0 then + input.logger("= hash append: %s",tag) + end + table.insert(input.instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } ) end -function input.aux.prepend_hash(instance,type,tag,name) - input.logger("= hash prepend",tag) - table.insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } ) +function input.aux.prepend_hash(type,tag,name) + if input.trace > 0 then + input.logger("= hash prepend: %s",tag) + end + table.insert(input.instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } ) end -function input.aux.extend_texmf_var(instance,specification) -- crap - if instance.environment['TEXMF'] then - input.report("extending environment variable TEXMF with", specification) - instance.environment['TEXMF'] = instance.environment['TEXMF']:gsub("^%{", function() - return "{" .. specification .. "," - end) - elseif instance.variables['TEXMF'] then - input.report("extending configuration variable TEXMF with", specification) - instance.variables['TEXMF'] = instance.variables['TEXMF']:gsub("^%{", function() - return "{" .. specification .. "," - end) +function input.aux.extend_texmf_var(specification) -- crap, we could better prepend the hash + local instance = input.instance +-- local t = input.expanded_path_list('TEXMF') -- full expansion + local t = input.split_path(input.env('TEXMF')) + table.insert(t,1,specification) + local newspec = table.join(t,";") + if instance.environment["TEXMF"] then + instance.environment["TEXMF"] = newspec + elseif instance.variables["TEXMF"] then + instance.variables["TEXMF"] = newspec else - input.report("setting configuration variable TEXMF to", specification) - instance.variables['TEXMF'] = "{" .. specification .. "}" - end - if instance.variables['TEXMF']:find("%,") and not instance.variables['TEXMF']:find("^%{") then - input.report("adding {} to complex TEXMF variable, best do that yourself") - instance.variables['TEXMF'] = "{" .. instance.variables['TEXMF'] .. "}" + -- weird end - input.expand_variables(instance) - input.reset_hashes(instance) + input.expand_variables() + input.reset_hashes() end -- locators -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)) +function input.locatelists() + local instance = input.instance + for _, path in pairs(input.clean_path_list('TEXMF')) do + input.report("locating list of %s",path) + input.locatedatabase(input.normalize_name(path)) end end -function input.locatedatabase(instance,specification) - return input.methodhandler('locators', instance, specification) +function input.locatedatabase(specification) + return input.methodhandler('locators', specification) end -function input.locators.tex(instance,specification) +function input.locators.tex(specification) if specification and specification ~= '' and lfs.isdir(specification) then - input.logger('! tex locator', specification..' found') - input.aux.append_hash(instance,'file',specification,filename) - else - input.logger('? tex locator', specification..' not found') + if input.trace > 0 then + input.logger('! tex locator found: %s',specification) + end + input.aux.append_hash('file',specification,filename) + elseif input.trace > 0 then + input.logger('? tex locator not found: %s',specification) end end -- hashers -function input.hashdatabase(instance,tag,name) - return input.methodhandler('hashers',instance,tag,name) +function input.hashdatabase(tag,name) + return input.methodhandler('hashers',tag,name) end -function input.loadfiles(instance) +function input.loadfiles() + local instance = input.instance instance.loaderror = false instance.files = { } if not instance.renewcache then for _, hash in ipairs(instance.hashes) do - input.hashdatabase(instance,hash.tag,hash.name) + input.hashdatabase(hash.tag,hash.name) if instance.loaderror then break end end end end -function input.hashers.tex(instance,tag,name) - input.aux.load_files(instance,tag) +function input.hashers.tex(tag,name) + input.aux.load_files(tag) end -- generators: -function input.loadlists(instance) - for _, hash in ipairs(instance.hashes) do - input.generatedatabase(instance,hash.tag) +function input.loadlists() + for _, hash in ipairs(input.instance.hashes) do + input.generatedatabase(hash.tag) end end -function input.generatedatabase(instance,specification) - return input.methodhandler('generators', instance, specification) +function input.generatedatabase(specification) + return input.methodhandler('generators', specification) end -do - - local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) +local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) - function input.generators.tex(instance,specification) - local tag = specification - if not instance.lsrmode and lfs and lfs.dir then - input.report("scanning path",specification) - instance.files[tag] = { } - local files = instance.files[tag] - local n, m, r = 0, 0, 0 - local spec = specification .. '/' - local attributes = lfs.attributes - local directory = lfs.dir - local small = instance.smallcache - local function action(path) - local mode, full - if path then - full = spec .. path .. '/' +function input.generators.tex(specification) + local instance = input.instance + local tag = specification + if not instance.lsrmode and lfs.dir then + input.report("scanning path %s",specification) + instance.files[tag] = { } + local files = instance.files[tag] + local n, m, r = 0, 0, 0 + local spec = specification .. '/' + local attributes = lfs.attributes + local directory = lfs.dir + local small = instance.smallcache + local function action(path) + local mode, full + if path then + full = spec .. path .. '/' + else + full = spec + end + for name in directory(full) do + if name:find("^%.") then + -- skip + -- elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%<%>%,%?\n\r\t]") then -- too much escaped + elseif weird:match(name) then + -- texio.write_nl("skipping " .. name) + -- skip else - full = spec - end - for name in directory(full) do - if name:find("^%.") then - -- skip - -- elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%<%>%,%?\n\r\t]") then -- too much escaped - elseif weird:match(name) then - -- texio.write_nl("skipping " .. name) - -- skip - else - mode = attributes(full..name,'mode') - if mode == "directory" then - m = m + 1 - if path then - action(path..'/'..name) - else - action(name) - end - elseif path and mode == 'file' then - n = n + 1 - local f = files[name] - if f then - if not small then - if type(f) == 'string' then - files[name] = { f, path } - else - f[#f+1] = path - end - end - else - files[name] = path - local lower = name:lower() - if name ~= lower then - files["remap:"..lower] = name - r = r + 1 - end - end + mode = attributes(full..name,'mode') + if mode == 'directory' then + m = m + 1 + if path then + action(path..'/'..name) + else + action(name) end - end - end - end - action() - 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 = '.' - local f = io.open(fullname) - if f then - instance.files[tag] = { } - local files = instance.files[tag] - local small = instance.smallcache - input.report("loading lsr file",fullname) - -- for line in f:lines() do -- much slower then the next one - for line in (f:read("*a")):gmatch("(.-)\n") do - if line:find("^[%a%d]") then - local fl = files[line] - if fl then + elseif path and mode == 'file' then + n = n + 1 + local f = files[name] + if f then if not small then - if type(fl) == 'string' then - files[line] = { fl, path } -- table + if type(f) == 'string' then + files[name] = { f, path } else - fl[#fl+1] = path + f[#f+1] = path end end else - files[line] = path -- string - local lower = line:lower() - if line ~= lower then - files["remap:"..lower] = line + files[name] = path + local lower = name:lower() + if name ~= lower then + files["remap:"..lower] = name + r = r + 1 + end + end + end + end + end + end + action() + input.report("%s files found on %s directories with %s uppercase remappings",n,m,r) + else + local fullname = file.join(specification,input.lsrname) + local path = '.' + local f = io.open(fullname) + if f then + instance.files[tag] = { } + local files = instance.files[tag] + local small = instance.smallcache + input.report("loading lsr file %s",fullname) + -- for line in f:lines() do -- much slower then the next one + for line in (f:read("*a")):gmatch("(.-)\n") do + if line:find("^[%a%d]") then + local fl = files[line] + if fl then + if not small then + if type(fl) == 'string' then + files[line] = { fl, path } -- table + else + fl[#fl+1] = path end end else - path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line + files[line] = path -- string + local lower = line:lower() + if line ~= lower then + files["remap:"..lower] = line + end end + else + path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line end - f:close() end + f:close() end end - end -- savers, todo -function input.savefiles(instance) - input.aux.save_data(instance, 'files', function(k,v) - return instance.validfile(k,v) -- path, name +function input.savefiles() + input.aux.save_data('files', function(k,v) + return input.instance.validfile(k,v) -- path, name end) end @@ -3451,8 +3739,8 @@ end -- we join them and split them after the expansion has taken place. This -- is more convenient. -function input.splitconfig(instance) - for i,c in ipairs(instance) do +function input.splitconfig() + for i,c in ipairs(input.instance) do for k,v in pairs(c) do if type(v) == 'string' then local t = file.split_path(v) @@ -3463,8 +3751,9 @@ function input.splitconfig(instance) end end end -function input.joinconfig(instance) - for i,c in ipairs(instance.order) do + +function input.joinconfig() + for i,c in ipairs(input.instance.order) do for k,v in pairs(c) do if type(v) == 'table' then c[k] = file.join_path(v) @@ -3487,8 +3776,9 @@ function input.join_path(str) end end -function input.splitexpansions(instance) - for k,v in pairs(instance.expansions) do +function input.splitexpansions() + local ie = input.instance.expansions + for k,v in pairs(ie) do local t, h = { }, { } for _,vv in pairs(file.split_path(v)) do if vv ~= "" and not h[vv] then @@ -3497,19 +3787,19 @@ function input.splitexpansions(instance) end end if #t > 1 then - instance.expansions[k] = t + ie[k] = t else - instance.expansions[k] = t[1] + ie[k] = t[1] end end end -- end of split/join code -function input.saveoldconfig(instance) - input.splitconfig(instance) - input.aux.save_data(instance, 'configuration', nil) - input.joinconfig(instance) +function input.saveoldconfig() + input.splitconfig() + input.aux.save_data('configuration', nil) + input.joinconfig() end input.configbanner = [[ @@ -3538,7 +3828,7 @@ function input.serialize(files) end end t[#t+1] = "return {" - if instance.sortdata then + if input.instance.sortdata then for _, k in pairs(sorted(files)) do local fk = files[k] if type(fk) == 'table' then @@ -3570,11 +3860,11 @@ 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 +function input.aux.save_data(dataname, check, makename) -- untested without cache overload + for cachename, files in pairs(input.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) + local luaname, lucname = name .. ".lua", name .. ".luc" + input.report("preparing %s for %s",dataname,cachename) 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 @@ -3592,38 +3882,38 @@ function input.aux.save_data(instance, dataname, check, makename) -- untested wi 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 - input.report("compiling failed for " .. dataname .. ", deleting file " .. lucname) + local ok = io.savedata(luaname,input.serialize(data)) + if ok then + input.report("%s saved in %s",dataname,luaname) + if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip + input.report("%s compiled to %s",dataname,lucname) + else + input.report("compiling failed for %s, deleting file %s",dataname,lucname) os.remove(lucname) end else - input.report("unable to save " .. dataname .. " in " .. name..input.luasuffix) + input.report("unable to save %s in %s (access error)",dataname,luaname) end end end -function input.aux.load_data(instance,pathname,dataname,filename,makename) -- untested without cache overload +function input.aux.load_data(pathname,dataname,filename,makename) -- untested without cache overload + local instance = input.instance 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) + local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua") 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) + input.report("loading %s for %s from %s",dataname,pathname,filename) instance[dataname][pathname] = data.content else - input.report("skipping",dataname,"for",pathname,"from",filename) + input.report("skipping %s for %s from %s",dataname,pathname,filename) instance[dataname][pathname] = { } instance.loaderror = true end else - input.report("skipping",dataname,"for",pathname,"from",filename) + input.report("skipping %s for %s from %s",dataname,pathname,filename) end end @@ -3636,13 +3926,14 @@ end -- TEXMFBOGUS = 'effe checken of dit werkt', -- } -function input.aux.load_texmfcnf(instance,dataname,pathname) +function input.aux.load_texmfcnf(dataname,pathname) + local instance = input.instance local filename = file.join(pathname,input.luaname) local blob = loadfile(filename) if blob then local data = blob() if data then - input.report("loading","configuration file",filename) + input.report("loading configuration file %s",filename) if true then -- flatten to variable.progname local t = { } @@ -3662,169 +3953,168 @@ function input.aux.load_texmfcnf(instance,dataname,pathname) instance[dataname][pathname] = data end else - input.report("skipping","configuration file",filename) + input.report("skipping configuration file %s",filename) instance[dataname][pathname] = { } instance.loaderror = true end else - input.report("skipping","configuration file",filename) + input.report("skipping configuration file %s",filename) end end -function input.aux.load_configuration(instance,dname,lname) - input.aux.load_data(instance,dname,'configuration',lname and file.basename(lname)) +function input.aux.load_configuration(dname,lname) + input.aux.load_data(dname,'configuration',lname and file.basename(lname)) end -function input.aux.load_files(instance,tag) - input.aux.load_data(instance,tag,'files') +function input.aux.load_files(tag) + input.aux.load_data(tag,'files') end -function input.resetconfig(instance) +function input.resetconfig() + input.identify_own() + local instance = input.instance instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false end -function input.loadnewconfig(instance) +function input.loadnewconfig() + local instance = input.instance for _, cnf in ipairs(instance.luafiles) do local dname = file.dirname(cnf) - input.aux.load_texmfcnf(instance,'setup',dname) + input.aux.load_texmfcnf('setup',dname) instance.order[#instance.order+1] = instance.setup[dname] if instance.loaderror then break end end end -function input.loadoldconfig(instance) +function input.loadoldconfig() + local instance = input.instance if not instance.renewcache then for _, cnf in ipairs(instance.cnffiles) do local dname = file.dirname(cnf) - input.aux.load_configuration(instance,dname) + input.aux.load_configuration(dname) instance.order[#instance.order+1] = instance.configuration[dname] if instance.loaderror then break end end end - input.joinconfig(instance) + input.joinconfig() end -function input.expand_variables(instance) - instance.expansions = { } ---~ 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 +function input.expand_variables() + local instance = input.instance + local expansions, environment, variables = { }, instance.environment, instance.variables + local env = input.env + instance.expansions = expansions + if instance.engine ~= "" then environment['engine'] = instance.engine end + if instance.progname ~= "" then environment['progname'] = instance.progname end + for k,v in pairs(environment) do local a, b = k:match("^(%a+)%_(.*)%s*$") if a and b then - instance.expansions[a..'.'..b] = v + expansions[a..'.'..b] = v else - instance.expansions[k] = v + expansions[k] = v end end - for k,v in pairs(instance.environment) do -- move environment to expansions - if not instance.expansions[k] then instance.expansions[k] = v end + for k,v in pairs(environment) do -- move environment to expansions + if not expansions[k] then expansions[k] = v end end - for k,v in pairs(instance.variables) do -- move variables to expansions - if not instance.expansions[k] then instance.expansions[k] = v end + for k,v in pairs(variables) do -- move variables to expansions + if not expansions[k] then expansions[k] = v end end while true do local busy = false - for k,v in pairs(instance.expansions) do + for k,v in pairs(expansions) do local s, n = v:gsub("%$([%a%d%_%-]+)", function(a) busy = true - return instance.expansions[a] or input.env(instance,a) + return expansions[a] or env(a) end) local s, m = s:gsub("%$%{([%a%d%_%-]+)%}", function(a) busy = true - return instance.expansions[a] or input.env(instance,a) + return expansions[a] or env(a) end) if n > 0 or m > 0 then - instance.expansions[k]= s + expansions[k]= s end end if not busy then break end end - for k,v in pairs(instance.expansions) do - instance.expansions[k] = v:gsub("\\", '/') + for k,v in pairs(expansions) do + expansions[k] = v:gsub("\\", '/') end end -function input.aux.expand_vars(instance,lst) -- simple vars +function input.aux.expand_vars(lst) -- simple vars + local instance = input.instance + local variables, env = instance.variables, input.env for k,v in pairs(lst) do lst[k] = v:gsub("%$([%a%d%_%-]+)", function(a) - return instance.variables[a] or input.env(instance,a) + return variables[a] or env(a) end) end end -function input.aux.expanded_var(instance,var) -- simple vars +function input.aux.expanded_var(var) -- simple vars + local instance = input.instance return var:gsub("%$([%a%d%_%-]+)", function(a) - return instance.variables[a] or input.env(instance,a) + return instance.variables[a] or input.env(a) end) end -function input.aux.entry(instance,entries,name) +function input.aux.entry(entries,name) if name and (name ~= "") then + local instance = input.instance name = name:gsub('%$','') local result = entries[name..'.'..instance.progname] or entries[name] if result then return result else - result = input.env(instance,name) + result = input.env(name) if result then instance.variables[name] = result - input.expand_variables(instance) + input.expand_variables() return instance.expansions[name] or "" end end end return "" end -function input.variable(instance,name) - return input.aux.entry(instance,instance.variables,name) +function input.variable(name) + return input.aux.entry(input.instance.variables,name) end -function input.expansion(instance,name) - return input.aux.entry(instance,instance.expansions,name) +function input.expansion(name) + return input.aux.entry(input.instance.expansions,name) end -function input.aux.is_entry(instance,entries,name) +function input.aux.is_entry(entries,name) if name and name ~= "" then name = name:gsub('%$','') - return (entries[name..'.'..instance.progname] or entries[name]) ~= nil + return (entries[name..'.'..input.instance.progname] or entries[name]) ~= nil else return false end end -function input.is_variable(instance,name) - return input.aux.is_entry(instance,instance.variables,name) -end -function input.is_expansion(instance,name) - return input.aux.is_entry(instance,instance.expansions,name) +function input.is_variable(name) + return input.aux.is_entry(input.instance.variables,name) end -function input.simplified_list(str) - if type(str) == 'table' then - return str -- troubles ; ipv , in texmf - elseif str == '' then - return { } - else - local t = { } - for _,v in ipairs(string.splitchr(str:gsub("^\{(.+)\}$","%1"),",")) do - t[#t+1] = (v:gsub("^[%!]*(.+)[%/\\]*$","%1")) - end - return t - end +function input.is_expansion(name) + return input.aux.is_entry(input.instance.expansions,name) end -function input.unexpanded_path_list(instance,str) - local pth = input.variable(instance,str) +function input.unexpanded_path_list(str) + local pth = input.variable(str) local lst = input.split_path(pth) - return input.aux.expanded_path(instance,lst) + return input.aux.expanded_path(lst) end -function input.unexpanded_path(instance,str) - return file.join_path(input.unexpanded_path_list(instance,str)) + +function input.unexpanded_path(str) + return file.join_path(input.unexpanded_path_list(str)) end do local done = { } - function input.reset_extra_path(instance) + function input.reset_extra_path() + local instance = input.instance local ep = instance.extra_paths if not ep then ep, done = { }, { } @@ -3834,7 +4124,8 @@ do end end - function input.register_extra_path(instance,paths,subpaths) + function input.register_extra_path(paths,subpaths) + local instance = input.instance local ep = instance.extra_paths or { } local n = #ep if paths and paths ~= "" then @@ -3879,7 +4170,8 @@ do end -function input.expanded_path_list(instance,str) +function input.expanded_path_list(str) + local instance = input.instance local function made_list(list) local ep = instance.extra_paths if not ep or #ep == 0 then @@ -3920,39 +4212,41 @@ function input.expanded_path_list(instance,str) -- engine+progname hash str = str:gsub("%$","") if not instance.lists[str] then -- cached - local lst = made_list(input.split_path(input.expansion(instance,str))) - instance.lists[str] = input.aux.expanded_path(instance,lst) + local lst = made_list(input.split_path(input.expansion(str))) + instance.lists[str] = input.aux.expanded_path(lst) end return instance.lists[str] else - local lst = input.split_path(input.expansion(instance,str)) - return made_list(input.aux.expanded_path(instance,lst)) + local lst = input.split_path(input.expansion(str)) + return made_list(input.aux.expanded_path(lst)) end end -function input.expand_path(instance,str) - return file.join_path(input.expanded_path_list(instance,str)) + +function input.clean_path_list(str) + local t = input.expanded_path_list(str) + if t then + for i=1,#t do + t[i] = file.collapse_path(input.clean_path(t[i])) + end + end + return t end ---~ function input.first_writable_path(instance,name) ---~ for _,v in pairs(input.expanded_path_list(instance,name)) do ---~ if file.is_writable(file.join(v,'luatex-cache.tmp')) then ---~ return v ---~ end ---~ end ---~ return "." ---~ end +function input.expand_path(str) + return file.join_path(input.expanded_path_list(str)) +end -function input.expanded_path_list_from_var(instance,str) -- brrr +function input.expanded_path_list_from_var(str) -- brrr local tmp = input.var_of_format_or_suffix(str:gsub("%$","")) if tmp ~= "" then - return input.expanded_path_list(instance,str) + return input.expanded_path_list(str) else - return input.expanded_path_list(instance,tmp) + return input.expanded_path_list(tmp) end end -function input.expand_path_from_var(instance,str) - return file.join_path(input.expanded_path_list_from_var(instance,str)) +function input.expand_path_from_var(str) + return file.join_path(input.expanded_path_list_from_var(str)) end function input.format_of_var(str) @@ -3982,9 +4276,9 @@ function input.var_of_format_or_suffix(str) return '' end -function input.expand_braces(instance,str) -- output variable and brace expansion of STRING - local ori = input.variable(instance,str) - local pth = input.aux.expanded_path(instance,input.split_path(ori)) +function input.expand_braces(str) -- output variable and brace expansion of STRING + local ori = input.variable(str) + local pth = input.aux.expanded_path(input.split_path(ori)) return file.join_path(pth) end @@ -3999,6 +4293,7 @@ end -- {a,b,c/{p,q,r}/d/{x,y,z}//} -- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}} -- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}} +-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c} -- this one is better and faster, but it took me a while to realize -- that this kind of replacement is cleaner than messy parsing and @@ -4007,19 +4302,20 @@ end -- work that well; the parsing is ok, but dealing with the resulting -- table is a pain because we need to work inside-out recursively --- get rid of piecewise here, just a gmatch is ok - function input.aux.splitpathexpr(str, t, validate) -- no need for optimization, only called a few times, we can use lpeg for the sub t = t or { } local concat = table.concat + str = str:gsub(",}",",@}") + str = str:gsub("{,","{@,") + -- str = "@" .. str .. "@" while true do local done = false while true do local ok = false - str = str:gsub("([^{},]+){([^{}]-)}", function(a,b) + str = str:gsub("([^{},]+){([^{}]+)}", function(a,b) local t = { } - b:piecewise(",", function(s) t[#t+1] = a .. s end) + for s in b:gmatch("[^,]+") do t[#t+1] = a .. s end ok, done = true, true return "{" .. concat(t,",") .. "}" end) @@ -4027,9 +4323,9 @@ function input.aux.splitpathexpr(str, t, validate) end while true do local ok = false - str = str:gsub("{([^{}]-)}([^{},]+)", function(a,b) + str = str:gsub("{([^{}]+)}([^{},]+)", function(a,b) local t = { } - a:piecewise(",", function(s) t[#t+1] = s .. b end) + for s in a:gmatch("[^,]+") do t[#t+1] = s .. b end ok, done = true, true return "{" .. concat(t,",") .. "}" end) @@ -4037,50 +4333,41 @@ function input.aux.splitpathexpr(str, t, validate) end while true do local ok = false - str = str:gsub("([,{]){([^{}]+)}([,}])", function(a,b,c) + str = str:gsub("{([^{}]+)}{([^{}]+)}", function(a,b) + local t = { } + for sa in a:gmatch("[^,]+") do + for sb in b:gmatch("[^,]+") do + t[#t+1] = sa .. sb + end + end ok, done = true, true - return a .. b .. c + return "{" .. concat(t,",") .. "}" end) if not ok then break end end - if not done then break end - end - while true do - local ok = false - str = str:gsub("{([^{}]-)}{([^{}]-)}", function(a,b) - local t = { } - a:piecewise(",", function(sa) - b:piecewise(",", function(sb) - t[#t+1] = sa .. sb - end) - end) - ok = true - return "{" .. concat(t,",") .. "}" - end) - if not ok then break end - end - while true do - local ok = false - str = str:gsub("{([^{}]-)}", function(a) - ok = true - return a + str = str:gsub("({[^{}]*){([^{}]+)}([^{}]*})", function(a,b,c) + done = true + return a .. b.. c end) - if not ok then break end + if not done then break end end + str = str:gsub("[{}]", "") + str = str:gsub("@","") if validate then - str:piecewise(",", function(s) + for s in str:gmatch("[^,]+") do s = validate(s) if s then t[#t+1] = s end - end) + end else - str:piecewise(",", function(s) + for s in str:gmatch("[^,]+") do t[#t+1] = s - end) + end end return t end -function input.aux.expanded_path(instance,pathlist) -- maybe not a list, just a path +function input.aux.expanded_path(pathlist) -- maybe not a list, just a path + local instance = input.instance -- a previous version fed back into pathlist local newlist, ok = { }, false for _,v in ipairs(pathlist) do @@ -4112,17 +4399,16 @@ input.is_readable = { } function input.aux.is_readable(readable, name) if input.trace > 2 then if readable then - input.logger("+ readable", name) + input.logger("+ readable: %s",name) else - input.logger("- readable", name) + input.logger("- readable: %s", name) end end return readable end function input.is_readable.file(name) - -- return input.aux.is_readable(file.is_readable(name), name) - return input.aux.is_readable(input.aux.is_file(name), name) + return input.aux.is_readable(lfs.isfile(name), name) end input.is_readable.tex = input.is_readable.file @@ -4130,12 +4416,13 @@ input.is_readable.tex = input.is_readable.file -- name -- name/name -function input.aux.collect_files(instance,names) +function input.aux.collect_files(names) + local instance = input.instance local filelist = { } for _, fname in pairs(names) do if fname then if input.trace > 2 then - input.logger("? blobpath asked",fname) + input.logger("? blobpath asked: %s",fname) end local bname = file.basename(fname) local dname = file.dirname(fname) @@ -4149,7 +4436,7 @@ function input.aux.collect_files(instance,names) local files = blobpath and instance.files[blobpath] if files then if input.trace > 2 then - input.logger('? blobpath do',blobpath .. " (" .. bname ..")") + input.logger('? blobpath do: %s (%s)',blobpath,bname) end local blobfile = files[bname] if not blobfile then @@ -4182,7 +4469,7 @@ function input.aux.collect_files(instance,names) end end elseif input.trace > 1 then - input.logger('! blobpath no',blobpath .. " (" .. bname ..")" ) + input.logger('! blobpath no: %s (%s)',blobpath,bname) end end end @@ -4237,15 +4524,17 @@ do end -function input.aux.register_in_trees(instance,name) +function input.aux.register_in_trees(name) if not name:find("^%.") then + local instance = input.instance instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one end end -- split the next one up, better for jit -function input.aux.find_file(instance,filename) -- todo : plugin (scanners, checkers etc) +function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc) + local instance = input.instance local result = { } local stamp = nil filename = input.normalize_name(filename) -- elsewhere @@ -4254,16 +4543,22 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format if instance.found[stamp] then - input.logger('! remembered', filename) + if input.trace > 0 then + input.logger('! remembered: %s',filename) + end return instance.found[stamp] end end if filename:find('%*') then - input.logger('! wildcard', filename) - result = input.find_wildcard_files(instance,filename) + if input.trace > 0 then + input.logger('! wildcard: %s', filename) + end + result = input.find_wildcard_files(filename) elseif input.aux.qualified_path(filename) then if input.is_readable.file(filename) then - input.logger('! qualified', filename) + if input.trace > 0 then + input.logger('! qualified: %s', filename) + end result = { filename } else local forcedname, ok = "", false @@ -4271,22 +4566,26 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec if instance.format == "" then forcedname = filename .. ".tex" if input.is_readable.file(forcedname) then - input.logger('! no suffix, forcing standard filetype tex') + if input.trace > 0 then + input.logger('! no suffix, forcing standard filetype: tex') + end result, ok = { forcedname }, true end else for _, s in pairs(input.suffixes_of_format(instance.format)) do forcedname = filename .. "." .. s if input.is_readable.file(forcedname) then - input.logger('! no suffix, forcing format filetype', s) + if input.trace > 0 then + input.logger('! no suffix, forcing format filetype: %s', s) + end result, ok = { forcedname }, true break end end end end - if not ok then - input.logger('? qualified', filename) + if not ok and input.trace > 0 then + input.logger('? qualified: %s', filename) end end else @@ -4304,10 +4603,14 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec local forcedname = filename .. '.tex' wantedfiles[#wantedfiles+1] = forcedname filetype = input.format_of_suffix(forcedname) - input.logger('! forcing filetype',filetype) + if input.trace > 0 then + input.logger('! forcing filetype: %s',filetype) + end else filetype = input.format_of_suffix(filename) - input.logger('! using suffix based filetype',filetype) + if input.trace > 0 then + input.logger('! using suffix based filetype: %s',filetype) + end end else if ext == "" then @@ -4316,16 +4619,18 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec end end filetype = instance.format - input.logger('! using given filetype',filetype) + if input.trace > 0 then + input.logger('! using given filetype: %s',filetype) + end end local typespec = input.variable_of_format(filetype) - local pathlist = input.expanded_path_list(instance,typespec) + local pathlist = input.expanded_path_list(typespec) if not pathlist or #pathlist == 0 then -- no pathlist, access check only / todo == wildcard if input.trace > 2 then - input.logger('? filename',filename) - input.logger('? filetype',filetype or '?') - input.logger('? wanted files',table.concat(wantedfiles," | ")) + input.logger('? filename: %s',filename) + input.logger('? filetype: %s',filetype or '?') + input.logger('? wanted files: %s',table.concat(wantedfiles," | ")) end for _, fname in pairs(wantedfiles) do if fname and input.is_readable.file(fname) then @@ -4335,7 +4640,7 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec end end -- this is actually 'other text files' or 'any' or 'whatever' - local filelist = input.aux.collect_files(instance,wantedfiles) + local filelist = input.aux.collect_files(wantedfiles) local fl = filelist and filelist[1] if fl then filename = fl[3] @@ -4344,12 +4649,12 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec end else -- list search - local filelist = input.aux.collect_files(instance,wantedfiles) + local filelist = input.aux.collect_files(wantedfiles) local doscan, recurse if input.trace > 2 then - input.logger('? filename',filename) - -- if pathlist then input.logger('? path list',table.concat(pathlist," | ")) end - -- if filelist then input.logger('? file list',table.concat(filelist," | ")) end + input.logger('? filename: %s',filename) + -- if pathlist then input.logger('? path list: %s',table.concat(pathlist," | ")) end + -- if filelist then input.logger('? file list: %s',table.concat(filelist," | ")) end end -- a bit messy ... esp the doscan setting here for _, path in pairs(pathlist) do @@ -4370,11 +4675,11 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec if f:find(expr) then -- input.debug('T',' '..f) if input.trace > 2 then - input.logger('= found in hash',f) + input.logger('= found in hash: %s',f) end --- todo, test for readable result[#result+1] = fl[3] - input.aux.register_in_trees(instance,f) -- for tracing used files + input.aux.register_in_trees(f) -- for tracing used files done = true if not instance.allresults then break end else @@ -4388,12 +4693,12 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec local pname = pathname:gsub("%.%*$",'') if not pname:find("%*") then local ppname = pname:gsub("/+$","") - if input.aux.can_be_dir(instance,ppname) then + if input.aux.can_be_dir(ppname) then for _, w in pairs(wantedfiles) do local fname = file.join(ppname,w) if input.is_readable.file(fname) then if input.trace > 2 then - input.logger('= found by scanning',fname) + input.logger('= found by scanning: %s',fname) end result[#result+1] = fname done = true @@ -4422,40 +4727,29 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec return result end -input.aux._find_file_ = input.aux.find_file +input.aux._find_file_ = input.aux.find_file -- frozen variant -function input.aux.find_file(instance,filename) -- maybe make a lowres cache too - local result = input.aux._find_file_(instance,filename) +function input.aux.find_file(filename) -- maybe make a lowres cache too + local result = input.aux._find_file_(filename) if #result == 0 then local lowered = filename:lower() if filename ~= lowered then - return input.aux._find_file_(instance,lowered) + return input.aux._find_file_(lowered) end end return result end -if lfs and lfs.isfile then - input.aux.is_file = lfs.isfile -- to be done: use this -else - input.aux.is_file = file.is_readable -end - -if lfs and lfs.isdir then - function input.aux.can_be_dir(instance,name) - if not instance.fakepaths[name] then - if lfs.isdir(name) then - instance.fakepaths[name] = 1 -- directory - else - instance.fakepaths[name] = 2 -- no directory - end +function input.aux.can_be_dir(name) + local instance = input.instance + if not instance.fakepaths[name] then + if lfs.isdir(name) then + instance.fakepaths[name] = 1 -- directory + else + instance.fakepaths[name] = 2 -- no directory end - return (instance.fakepaths[name] == 1) - end -else - function input.aux.can_be_dir() - return true end + return (instance.fakepaths[name] == 1) end if not input.concatinators then input.concatinators = { } end @@ -4463,7 +4757,8 @@ if not input.concatinators then input.concatinators = { } end input.concatinators.tex = file.join input.concatinators.file = input.concatinators.tex -function input.find_files(instance,filename,filetype,mustexist) +function input.find_files(filename,filetype,mustexist) + local instance = input.instance if type(mustexist) == boolean then -- all set elseif type(filetype) == 'boolean' then @@ -4472,16 +4767,17 @@ function input.find_files(instance,filename,filetype,mustexist) filetype, mustexist = nil, false end instance.format = filetype or '' - local t = input.aux.find_file(instance,filename,true) + local t = input.aux.find_file(filename,true) instance.format = '' return t end -function input.find_file(instance,filename,filetype,mustexist) - return (input.find_files(instance,filename,filetype,mustexist)[1] or "") +function input.find_file(filename,filetype,mustexist) + return (input.find_files(filename,filetype,mustexist)[1] or "") end -function input.find_given_files(instance,filename) +function input.find_given_files(filename) + local instance = input.instance local bname, result = file.basename(filename), { } for k, hash in ipairs(instance.hashes) do local files = instance.files[hash.tag] @@ -4509,11 +4805,12 @@ function input.find_given_files(instance,filename) return result end -function input.find_given_file(instance,filename) - return (input.find_given_files(instance,filename)[1] or "") +function input.find_given_file(filename) + return (input.find_given_files(filename)[1] or "") end -function input.find_wildcard_files(instance,filename) -- todo: remap: +function input.find_wildcard_files(filename) -- todo: remap: + local instance = input.instance local result = { } local bname, dname = file.basename(filename), file.dirname(filename) local path = dname:gsub("^*/","") @@ -4569,13 +4866,14 @@ function input.find_wildcard_files(instance,filename) -- todo: remap: return result end -function input.find_wildcard_file(instance,filename) - return (input.find_wildcard_files(instance,filename)[1] or "") +function input.find_wildcard_file(filename) + return (input.find_wildcard_files(filename)[1] or "") end -- main user functions -function input.save_used_files_in_trees(instance, filename,jobname) +function input.save_used_files_in_trees(filename,jobname) + local instance = input.instance if not filename then filename = 'luatex.jlg' end local f = io.open(filename,'w') if f then @@ -4594,24 +4892,24 @@ function input.save_used_files_in_trees(instance, filename,jobname) end end -function input.automount(instance) +function input.automount() -- implemented later 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) - input.automount(instance) - input.stoptiming(instance) +function input.load() + input.starttiming(input.instance) + input.resetconfig() + input.identify_cnf() + input.load_lua() + input.expand_variables() + input.load_cnf() + input.expand_variables() + input.load_hash() + input.automount() + input.stoptiming(input.instance) end -function input.for_files(instance, command, files, filetype, mustexist) +function input.for_files(command, files, filetype, mustexist) if files and #files > 0 then local function report(str) if input.verbose then @@ -4624,7 +4922,7 @@ function input.for_files(instance, command, files, filetype, mustexist) report('') end for _, file in pairs(files) do - local result = command(instance,file,filetype,mustexist) + local result = command(file,filetype,mustexist) if type(result) == 'string' then report(result) else @@ -4638,14 +4936,11 @@ end -- strtab -function input.var_value(instance,str) -- output the value of variable $STRING. - return input.variable(instance,str) -end -function input.expand_var(instance,str) -- output variable expansion of STRING. - return input.expansion(instance,str) -end -function input.show_path(instance,str) -- output search path for file type NAME - return file.join_path(input.expanded_path_list(instance,input.format_of_var(str))) +input.var_value = input.variable -- output the value of variable $STRING. +input.expand_var = input.expansion -- output variable expansion of STRING. + +function input.show_path(str) -- output search path for file type NAME + return file.join_path(input.expanded_path_list(input.format_of_var(str))) end -- input.find_file(filename) @@ -4697,53 +4992,55 @@ function table.sequenced(t,sep) -- temp here return table.concat(s, sep or " | ") end -function input.methodhandler(what, instance, filename, filetype) -- ... +function input.methodhandler(what, filename, filetype) -- ... local specification = (type(filename) == "string" and input.splitmethod(filename)) or filename -- no or { }, let it bomb local scheme = specification.scheme if input[what][scheme] then - input.logger('= handler',specification.original .." -> " .. what .. " -> " .. table.sequenced(specification)) - return input[what][scheme](instance,filename,filetype) -- todo: specification + if input.trace > 0 then + input.logger('= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification)) + end + return input[what][scheme](filename,filetype) -- todo: specification else - return input[what].tex(instance,filename,filetype) -- todo: specification + return input[what].tex(filename,filetype) -- todo: specification end end -- also inside next test? -function input.findtexfile(instance, filename, filetype) - return input.methodhandler('finders',instance, input.normalize_name(filename), filetype) +function input.findtexfile(filename, filetype) + return input.methodhandler('finders',input.normalize_name(filename), filetype) end -function input.opentexfile(instance,filename) - return input.methodhandler('openers',instance, input.normalize_name(filename)) +function input.opentexfile(filename) + return input.methodhandler('openers',input.normalize_name(filename)) end -function input.findbinfile(instance, filename, filetype) - return input.methodhandler('finders',instance, input.normalize_name(filename), filetype) +function input.findbinfile(filename, filetype) + return input.methodhandler('finders',input.normalize_name(filename), filetype) end -function input.openbinfile(instance,filename) - return input.methodhandler('loaders',instance, input.normalize_name(filename)) +function input.openbinfile(filename) + return input.methodhandler('loaders',input.normalize_name(filename)) end -function input.loadbinfile(instance, filename, filetype) - local fname = input.findbinfile(instance, input.normalize_name(filename), filetype) +function input.loadbinfile(filename, filetype) + local fname = input.findbinfile(input.normalize_name(filename), filetype) if fname and fname ~= "" then - return input.openbinfile(instance,fname) + return input.openbinfile(fname) else return unpack(input.loaders.notfound) end end -function input.texdatablob(instance, filename, filetype) - local ok, data, size = input.loadbinfile(instance, filename, filetype) +function input.texdatablob(filename, filetype) + local ok, data, size = input.loadbinfile(filename, filetype) return data or "" end input.loadtexfile = input.texdatablob -function input.openfile(filename) -- brrr texmf.instance here / todo ! ! ! ! ! - local fullname = input.findtexfile(texmf.instance, filename) +function input.openfile(filename) + local fullname = input.findtexfile(filename) if fullname and (fullname ~= "") then - return input.opentexfile(texmf.instance, fullname) + return input.opentexfile(fullname) else return nil end @@ -4789,16 +5086,18 @@ end -- beware: i need to check where we still need a / on windows: function input.clean_path(str) ---~ return (((str:gsub("\\","/")):gsub("^!+","")):gsub("//+","//")) if str then - return ((str:gsub("\\","/")):gsub("^!+","")) + str = str:gsub("\\","/") + str = str:gsub("^!+","") + str = str:gsub("^~",input.homedir) + return str else return nil end end function input.do_with_path(name,func) - for _, v in pairs(input.expanded_path_list(instance,name)) do + for _, v in pairs(input.expanded_path_list(name)) do func("^"..input.clean_path(v)) end end @@ -4807,7 +5106,8 @@ function input.do_with_var(name,func) func(input.aux.expanded_var(name)) end -function input.with_files(instance,pattern,handle) +function input.with_files(pattern,handle) + local instance = input.instance for _, hash in ipairs(instance.hashes) do local blobpath = hash.tag local blobtype = hash.type @@ -4834,37 +5134,22 @@ function input.with_files(instance,pattern,handle) end end ---~ function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix ---~ newname = file.addsuffix(newname,"lua") ---~ local newscript = input.clean_path(input.find_file(instance, newname)) ---~ local oldscript = input.clean_path(oldname) ---~ input.report("old script", oldscript) ---~ input.report("new script", newscript) ---~ if oldscript ~= newscript and (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then ---~ local newdata = io.loaddata(newscript) ---~ if newdata then ---~ input.report("old script content replaced by new content") ---~ io.savedata(oldscript,newdata) ---~ end ---~ end ---~ end - -function input.update_script(instance,oldname,newname) -- oldname -> own.name, not per se a suffix +function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix local scriptpath = "scripts/context/lua" newname = file.addsuffix(newname,"lua") local oldscript = input.clean_path(oldname) - input.report("to be replaced old script", oldscript) - local newscripts = input.find_files(instance, newname) or { } + input.report("to be replaced old script %s", oldscript) + local newscripts = input.find_files(newname) or { } if #newscripts == 0 then input.report("unable to locate new script") else for _, newscript in ipairs(newscripts) do newscript = input.clean_path(newscript) - input.report("checking new script", newscript) + input.report("checking new script %s", newscript) if oldscript == newscript then input.report("old and new script are the same") elseif not newscript:find(scriptpath) then - input.report("new script should come from",scriptpath) + input.report("new script should come from %s",scriptpath) elseif not (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then input.report("invalid new script name") else @@ -4892,10 +5177,10 @@ do local resolvers = { } - resolvers.environment = function(instance,str) + resolvers.environment = function(str) return input.clean_path(os.getenv(str) or os.getenv(str:upper()) or os.getenv(str:lower()) or "") end - resolvers.relative = function(instance,str,n) + resolvers.relative = function(str,n) if io.exists(str) then -- nothing elseif io.exists("./" .. str) then @@ -4913,16 +5198,16 @@ do end return input.clean_path(str) end - resolvers.locate = function(instance,str) - local fullname = input.find_given_file(instance,str) or "" + resolvers.locate = function(str) + local fullname = input.find_given_file(str) or "" return input.clean_path((fullname ~= "" and fullname) or str) end - resolvers.filename = function(instance,str) - local fullname = input.find_given_file(instance,str) or "" + resolvers.filename = function(str) + local fullname = input.find_given_file(str) or "" return input.clean_path(file.basename((fullname ~= "" and fullname) or str)) end - resolvers.pathname = function(instance,str) - local fullname = input.find_given_file(instance,str) or "" + resolvers.pathname = function(str) + local fullname = input.find_given_file(str) or "" return input.clean_path(file.dirname((fullname ~= "" and fullname) or str)) end @@ -4934,15 +5219,15 @@ do resolvers.file = resolvers.filename resolvers.path = resolvers.pathname - local function resolve(instance,str) + local function resolve(str) if type(str) == "table" then for k, v in pairs(str) do - str[k] = resolve(instance,v) or v + str[k] = resolve(v) or v end elseif str and str ~= "" then - str = str:gsub("([a-z]+):([^ ]+)", function(method,target) + str = str:gsub("([a-z]+):([^ ]*)", function(method,target) if resolvers[method] then - return resolvers[method](instance,target) + return resolvers[method](target) else return method .. ":" .. target end @@ -4951,10 +5236,173 @@ do return str end + if os.uname then + for k, v in pairs(os.uname()) do + if not resolvers[k] then + resolvers[k] = function() return v end + end + end + end + input.resolve = resolve end +function input.boolean_variable(str,default) + local b = input.expansion("PURGECACHE") + if b == "" then + return default + else + b = toboolean(b) + return (b == nil and default) or b + end +end + + +if not modules then modules = { } end modules ['luat-log'] = { + version = 1.001, + comment = "companion to luat-lib.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +--[[ldx-- +<p>This is a prelude to a more extensive logging module. For the sake +of parsing log files, in addition to the standard logging we will +provide an <l n='xml'/> structured file. Actually, any logging that +is hooked into callbacks will be \XML\ by default.</p> +--ldx]]-- + +-- input.logger -> special tracing, driven by log level (only input) +-- input.report -> goes to terminal, depends on verbose, has banner +-- logs.report -> module specific tracing and reporting, no banner but class + + +input = input or { } +logs = logs or { } + +--[[ldx-- +<p>This looks pretty ugly but we need to speed things up a bit.</p> +--ldx]]-- + +logs.levels = { + ['error'] = 1, + ['warning'] = 2, + ['info'] = 3, + ['debug'] = 4 +} + +logs.functions = { + 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct' +} + +logs.callbacks = { + 'start_page_number', + 'stop_page_number', + 'report_output_pages', + 'report_output_log' +} + +logs.tracers = { +} + +logs.xml = logs.xml or { } +logs.tex = logs.tex or { } + +logs.level = 0 + +local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format + +if texlua then + write_nl = print + write = io.write +end + +function logs.xml.report(category,fmt,...) -- new + write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...))) +end +function logs.xml.line(fmt,...) -- new + write_nl(format("<r>%s</r>",format(fmt,...))) +end + +function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end +function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end +function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end +function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end + +function logs.tex.report(category,fmt,...) -- new + -- write_nl(format("%s | %s",category,format(fmt,...))) -- arg to format can be tex comment so .. . + write_nl(category .. " | " .. format(fmt,...)) +end +function logs.tex.line(fmt,...) -- new + write_nl(format(fmt,...)) +end + +function logs.set_level(level) + logs.level = logs.levels[level] or level +end + +function logs.set_method(method) + for _, v in pairs(logs.functions) do + logs[v] = logs[method][v] or function() end + end + if callback and input[method] then + for _, cb in pairs(logs.callbacks) do + callback.register(cb, input[method][cb]) + end + end +end + +function logs.xml.start_page_number() + write_nl(format("<p real='%s' page='%s' sub='%s'", tex.count[0], tex.count[1], tex.count[2])) +end + +function logs.xml.stop_page_number() + write("/>") + write_nl("") +end + +function logs.xml.report_output_pages(p,b) + write_nl(format("<v k='pages' v='%s'/>", p)) + write_nl(format("<v k='bytes' v='%s'/>", b)) + write_nl("") +end + +function logs.xml.report_output_log() +end + +function input.logger(...) -- assumes test for input.trace > n + if input.trace > 0 then + logs.report(...) + end +end + +function input.report(fmt,...) + if input.verbose then + logs.report(input.banner or "report",format(fmt,...)) + end +end + +function input.reportlines(str) -- todo: <lines></lines> + for line in str:gmatch("(.-)[\n\r]") do + logs.report(input.banner or "report",line) + end +end + +function input.help(banner,message) + if not input.verbose then + input.verbose = true + -- input.report(banner,"\n") + end + input.report(banner,"\n") + input.report("") + input.reportlines(message) +end + +logs.set_level('error') +logs.set_method('tex') + if not modules then modules = { } end modules ['luat-tmp'] = { version = 1.001, @@ -4980,63 +5428,82 @@ being written at the same time is small. We also need to extend luatools with a recache feature.</p> --ldx]]-- +local format = string.format + caches = caches or { } dir = dir or { } texmf = texmf or { } -caches.path = caches.path or nil -caches.base = caches.base or "luatex-cache" -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.paths = caches.paths or nil -caches.force = false - -input.usecache = not toboolean(os.getenv("TEXMFSHARECACHE") or "false",true) -- true - -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 +caches.path = caches.path or nil +caches.base = caches.base or "luatex-cache" +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.paths = caches.paths or nil +caches.force = false +caches.defaults = { "TEXMFCACHE", "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" } + +function caches.temp() + local cachepath = nil + local function check(list,isenv) + if not cachepath then + for _, v in ipairs(list) do + cachepath = (isenv and (os.env[v] or "")) or v or "" + if cachepath == "" then + -- next + else + cachepath = input.clean_path(cachepath) + if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory" + break + elseif caches.force or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then + dir.mkdirs(cachepath) + if lfs.isdir(cachepath) and file.iswritable(cachepath) then + break + end + end + end + cachepath = nil + end end end - 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 + check(input.clean_path_list("TEXMFCACHE") or { }) + check(caches.defaults,true) if not cachepath then - print("\nfatal error: there is no valid cache path defined\n") + print("\nfatal error: there is no valid (writable) 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)) + elseif not lfs.isdir(cachepath) then -- lfs.attributes(cachepath,"mode") ~= "directory" + print(format("\nfatal error: cache path %s is not a directory\n",cachepath)) os.exit() end - function caches.temp(instance) + cachepath = input.normalize_name(cachepath) + function caches.temp() return cachepath end return cachepath end -function caches.configpath(instance) - return table.concat(instance.cnffiles,";") +function caches.configpath() + return table.concat(input.instance.cnffiles,";") end function caches.hashed(tree) return md5.hex((tree:lower()):gsub("[\\\/]+","/")) end -function caches.treehash(instance) - local tree = caches.configpath(instance) +--~ tracing: + +--~ function caches.hashed(tree) +--~ tree = (tree:lower()):gsub("[\\\/]+","/") +--~ local hash = md5.hex(tree) +--~ if input.verbose then -- temp message +--~ input.report("hashing %s => %s",tree,hash) +--~ end +--~ return hash +--~ end + +function caches.treehash() + local tree = caches.configpath() if not tree or tree == "" then return false else @@ -5044,14 +5511,14 @@ function caches.treehash(instance) end end -function caches.setpath(instance,...) +function caches.setpath(...) if not caches.path then if not caches.path then - caches.path = caches.temp(instance) + caches.path = caches.temp() end caches.path = input.clean_path(caches.path) -- to be sure if lfs then - caches.tree = caches.tree or caches.treehash(instance) + caches.tree = caches.tree or caches.treehash() if caches.tree then caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree) else @@ -5071,9 +5538,9 @@ function caches.setpath(instance,...) return caches.path end -function caches.definepath(instance,category,subcategory) +function caches.definepath(category,subcategory) return function() - return caches.setpath(instance,category,subcategory) + return caches.setpath(category,subcategory) end end @@ -5096,26 +5563,38 @@ function caches.is_writable(filepath,filename) return file.is_writable(tmaname) end -function caches.savedata(filepath,filename,data,raw) -- raw needed for file cache +function input.boolean_variable(str,default) + local b = input.expansion("PURGECACHE") + if b == "" then + return default + else + b = toboolean(b) + return (b == nil and default) or b + end +end + +function caches.savedata(filepath,filename,data,raw) local tmaname, tmcname = caches.setluanames(filepath,filename) local reduce, simplify = true, true if raw then reduce, simplify = false, false end if caches.direct then - file.savedata(tmaname, table.serialize(data,'return',true,true)) + file.savedata(tmaname, table.serialize(data,'return',true,true,false)) -- no hex else - table.tofile (tmaname, data,'return',true,true) -- maybe not the last true + table.tofile(tmaname, data,'return',true,true,false) -- maybe not the last true end - utils.lua.compile(tmaname, tmcname) + local cleanup = input.boolean_variable("PURGECACHE", false) + local strip = input.boolean_variable("LUACSTRIP", true) + utils.lua.compile(tmaname, tmcname, cleanup, strip) end -- here we use the cache for format loading (texconfig.[formatname|jobname]) --~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then -if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and texmf.instance then +if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and input.instance then if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc - texconfig.formatname = caches.setpath(texmf.instance,"formats") .. "/" .. texconfig.luaname:gsub("%.lu.$",".fmt") + texconfig.formatname = caches.setpath("formats") .. "/" .. texconfig.luaname:gsub("%.lu.$",".fmt") end --[[ldx-- @@ -5138,7 +5617,7 @@ do -- local report local function report(container,tag,name) if caches.trace or containers.trace or container.trace then - logs.report(string.format("%s cache",container.subcategory),string.format("%s: %s",tag,name or 'invalid')) + logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid') end end @@ -5163,7 +5642,7 @@ do -- local report enabled = enabled, version = version or 1.000, trace = false, - path = caches.setpath(texmf.instance,category,subcategory), + path = caches.setpath(category,subcategory), } c[subcategory] = s end @@ -5228,13 +5707,16 @@ end -- reimplement the saver. local save_data = input.aux.save_data +local load_data = input.aux.load_data -input.cachepath = nil +input.cachepath = nil -- public, for tracing +input.usecache = true -- public, for tracing -function input.aux.save_data(instance, dataname, check) - input.cachepath = input.cachepath or caches.definepath(instance,"trees") - save_data(instance, dataname, check, function(cachename,dataname) +function input.aux.save_data(dataname, check) + save_data(dataname, check, function(cachename,dataname) + input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true) if input.usecache then + input.cachepath = input.cachepath or caches.definepath("trees") return file.join(input.cachepath(),caches.hashed(cachename)) else return file.join(cachename,dataname) @@ -5242,12 +5724,11 @@ function input.aux.save_data(instance, dataname, check) end) end -local load_data = input.aux.load_data - -function input.aux.load_data(instance,pathname,dataname,filename) - input.cachepath = input.cachepath or caches.definepath(instance,"trees") - load_data(instance,pathname,dataname,filename,function(dataname,filename) +function input.aux.load_data(pathname,dataname,filename) + load_data(pathname,dataname,filename,function(dataname,filename) + input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true) if input.usecache then + input.cachepath = input.cachepath or caches.definepath("trees") return file.join(input.cachepath(),caches.hashed(pathname)) else if not filename or (filename == "") then @@ -5262,13 +5743,13 @@ end input.automounted = input.automounted or { } -function input.automount(instance,usecache) - local mountpaths = input.simplified_list(input.expansion(instance,'TEXMFMOUNT')) +function input.automount(usecache) + local mountpaths = input.clean_path_list(input.expansion('TEXMFMOUNT')) if table.is_empty(mountpaths) and usecache then - mountpaths = { caches.setpath(instance,"mount") } + mountpaths = { caches.setpath("mount") } end if not table.is_empty(mountpaths) then - input.starttiming(instance) + input.starttiming(input.instance) for k, root in pairs(mountpaths) do local f = io.open(root.."/url.tmi") if f then @@ -5277,16 +5758,16 @@ function input.automount(instance,usecache) if line:find("^[%%#%-]") then -- or %W -- skip elseif line:find("^zip://") then - input.report("mounting",line) + input.report("mounting %s",line) table.insert(input.automounted,line) - input.usezipfile(instance,line) + input.usezipfile(line) end end end f:close() end end - input.stoptiming(instance) + input.stoptiming(input.instance) end end @@ -5335,17 +5816,17 @@ function input.storage.dump() else name = str end - initialize = string.format("%s %s = %s or {} ", initialize, name, name) + initialize = format("%s %s = %s or {} ", initialize, name, name) end if evaluate then finalize = "input.storage.evaluate(" .. name .. ")" end input.storage.max = input.storage.max + 1 if input.storage.trace then - logs.report('storage',string.format('saving %s in slot %s',message,input.storage.max)) + logs.report('storage','saving %s in slot %s',message,input.storage.max) code = initialize .. - string.format("logs.report('storage','restoring %s from slot %s') ",message,input.storage.max) .. + format("logs.report('storage','restoring %s from slot %s') ",message,input.storage.max) .. table.serialize(original,name) .. finalize else @@ -5374,6 +5855,8 @@ end if not versions then versions = { } end versions['luat-zip'] = 1.001 +local format = string.format + if zip and input then zip.supported = true else @@ -5405,7 +5888,7 @@ else zip.archives = { } zip.registeredfiles = { } - function zip.openarchive(instance,name) + function zip.openarchive(name) if not name or name == "" then return nil else @@ -5413,7 +5896,7 @@ else if arch then return arch else - local full = input.find_file(instance,name) or "" + local full = input.find_file(name) or "" local arch = (full ~= "" and zip.open(full)) or false zip.archives[name] = arch return arch @@ -5421,7 +5904,7 @@ else end end - function zip.closearchive(instance,name) + function zip.closearchive(name) if not name or name == "" and zip.archives[name] then zip.close(zip.archives[name]) zip.archives[name] = nil @@ -5432,20 +5915,22 @@ else -- zip:///texmf.zip?tree=/tex/texmf-local -- zip:///texmf-mine.zip?tree=/tex/texmf-projects - function input.locators.zip(instance,specification) -- where is this used? startup zips (untested) + function input.locators.zip(specification) -- where is this used? startup zips (untested) specification = input.splitmethod(specification) local zipfile = specification.path - local zfile = zip.openarchive(instance,name) -- tricky, could be in to be initialized tree - if zfile then - input.logger('! zip locator', specification.original ..' found') - else - input.logger('? zip locator', specification.original ..' not found') + local zfile = zip.openarchive(name) -- tricky, could be in to be initialized tree + if input.trace > 0 then + if zfile then + input.logger('! zip locator, found: %s',specification.original) + else + input.logger('? zip locator, not found: %s',specification.original) + end end end - function input.hashers.zip(instance,tag,name) - input.report("loading zip file",name,"as",tag) - input.usezipfile(instance,tag .."?tree=" .. name) + function input.hashers.zip(tag,name) + input.report("loading zip file %s as %s",name,tag) + input.usezipfile(tag .."?tree=" .. name) end function input.concatinators.zip(tag,path,name) @@ -5460,101 +5945,124 @@ else return true end - function input.finders.zip(instance,specification,filetype) + function input.finders.zip(specification,filetype) specification = input.splitmethod(specification) if specification.path then local q = url.query(specification.query) if q.name then - local zfile = zip.openarchive(instance,specification.path) + local zfile = zip.openarchive(specification.path) if zfile then - input.logger('! zip finder',specification.path) + if input.trace > 0 then + input.logger('! zip finder, path: %s',specification.path) + end local dfile = zfile:open(q.name) if dfile then dfile = zfile:close() - input.logger('+ zip finder',q.name) + if input.trace > 0 then + input.logger('+ zip finder, name: %s',q.name) + end return specification.original end - else - input.logger('? zip finder',specification.path) + elseif input.trace > 0 then + input.logger('? zip finder, path %s',specification.path) end end end - input.logger('- zip finder',filename) + if input.trace > 0 then + input.logger('- zip finder, name: %s',filename) + end return unpack(input.finders.notfound) end - function input.openers.zip(instance,specification) + function input.openers.zip(specification) local zipspecification = input.splitmethod(specification) if zipspecification.path then local q = url.query(zipspecification.query) if q.name then - local zfile = zip.openarchive(instance,zipspecification.path) + local zfile = zip.openarchive(zipspecification.path) if zfile then - input.logger('+ zip starter',zipspecification.path) + if input.trace > 0 then + input.logger('+ zip starter, path: %s',zipspecification.path) + end local dfile = zfile:open(q.name) if dfile then input.show_open(specification) return input.openers.text_opener(specification,dfile,'zip') end - else - input.logger('- zip starter',zipspecification.path) + elseif input.trace > 0 then + input.logger('- zip starter, path %s',zipspecification.path) end end end - input.logger('- zip opener',filename) + if input.trace > 0 then + input.logger('- zip opener, name: %s',filename) + end return unpack(input.openers.notfound) end - function input.loaders.zip(instance,specification) + function input.loaders.zip(specification) specification = input.splitmethod(specification) if specification.path then local q = url.query(specification.query) if q.name then - local zfile = zip.openarchive(instance,specification.path) + local zfile = zip.openarchive(specification.path) if zfile then - input.logger('+ zip starter',specification.path) + if input.trace > 0 then + input.logger('+ zip starter, path: %s',specification.path) + end local dfile = zfile:open(q.name) if dfile then input.show_load(filename) - input.logger('+ zip loader',filename) + if input.trace > 0 then + input.logger('+ zip loader, name: %s',filename) + end local s = dfile:read("*all") dfile:close() return true, s, #s end - else - input.logger('- zip starter',specification.path) + elseif input.trace > 0 then + input.logger('- zip starter, path: %s',specification.path) end end end - input.logger('- zip loader',filename) + if input.trace > 0 then + input.logger('- zip loader, name: %s',filename) + end return unpack(input.openers.notfound) end -- zip:///somefile.zip -- zip:///somefile.zip?tree=texmf-local -> mount - function input.usezipfile(instance,zipname) + function input.usezipfile(zipname) zipname = validzip(zipname) - input.logger('! zip use','file '..zipname) + if input.trace > 0 then + input.logger('! zip use, file: %s',zipname) + end local specification = input.splitmethod(zipname) local zipfile = specification.path if zipfile and not zip.registeredfiles[zipname] then local tree = url.query(specification.query).tree or "" - input.logger('! zip register','file '..zipname) - local z = zip.openarchive(instance,zipfile) + if input.trace > 0 then + input.logger('! zip register, file: %s',zipname) + end + local z = zip.openarchive(zipfile) if z then - input.logger("= zipfile","registering "..zipname) + local instance = input.instance + if input.trace > 0 then + input.logger("= zipfile, registering: %s",zipname) + end input.starttiming(instance) - input.aux.prepend_hash(instance,'zip',zipname,zipfile) - input.aux.extend_texmf_var(instance,zipname) -- resets hashes too + input.aux.prepend_hash('zip',zipname,zipfile) + input.aux.extend_texmf_var(zipname) -- resets hashes too zip.registeredfiles[zipname] = z instance.files[zipname] = input.aux.register_zip_file(z,tree or "") input.stoptiming(instance) - else - input.logger("? zipfile","unknown "..zipname) + elseif input.trace > 0 then + input.logger("? zipfile, unknown: %s",zipname) end - else - input.logger('! zip register','no file '..zipname) + elseif input.trace > 0 then + input.logger('! zip register, no file: %s',zipname) end end @@ -5565,7 +6073,9 @@ else else filter = "^"..tree.."/(.+)/(.-)$" end - input.logger('= zip filter',filter) + if input.trace > 0 then + input.logger('= zip filter: %s',filter) + end local register, n = input.aux.register_file, 0 for i in z:files() do local path, name = i.filename:match(filter) @@ -5581,7 +6091,7 @@ else n = n + 1 end end - input.report('= zip entries',n) + input.logger('= zip entries: %s',n) return files end @@ -5598,6 +6108,8 @@ if not versions then versions = { } end versions['luat-tex'] = 1.001 -- special functions that deal with io +local format = string.format + if texconfig and not texlua then input.level = input.level or 0 @@ -5620,13 +6132,17 @@ if texconfig and not texlua then function input.show_load () end end - function input.finders.generic(instance,tag,filename,filetype) - local foundname = input.find_file(instance,filename,filetype) + function input.finders.generic(tag,filename,filetype) + local foundname = input.find_file(filename,filetype) if foundname and foundname ~= "" then - input.logger('+ ' .. tag .. ' finder',filename,'filetype') + if input.trace > 0 then + input.logger('+ finder: %s, file: %s', tag,filename) + end return foundname else - input.logger('- ' .. tag .. ' finder',filename,'filetype') + if input.trace > 0 then + input.logger('- finder: %s, file: %s', tag,filename) + end return unpack(input.finders.notfound) end end @@ -5639,7 +6155,9 @@ if texconfig and not texlua then local u = unicode.utftype(file_handle) local t = { } if u > 0 then - input.logger('+ ' .. tag .. ' opener (' .. unicode.utfname[u] .. ')',filename) + if input.trace > 0 then + input.logger('+ opener: %s (%s), file: %s',tag,unicode.utfname[u],filename) + end local l if u > 2 then l = unicode.utf32_to_utf8(file_handle:read("*a"),u==4) @@ -5654,7 +6172,9 @@ if texconfig and not texlua then handle = nil, noflines = #l, close = function() - input.logger('= ' .. tag .. ' closer (' .. unicode.utfname[u] .. ')',filename) + if input.trace > 0 then + input.logger('= closer: %s (%s), file: %s',tag,unicode.utfname[u],filename) + end input.show_close(filename) end, --~ getline = function(n) @@ -5690,7 +6210,9 @@ if texconfig and not texlua then end } else - input.logger('+ ' .. tag .. ' opener',filename) + if input.trace > 0 then + input.logger('+ opener: %s, file: %s',tag,filename) + end -- todo: file;name -> freeze / eerste regel scannen -> freeze local filters = input.filters t = { @@ -5710,7 +6232,9 @@ if texconfig and not texlua then return line end, close = function() - input.logger('= ' .. tag .. ' closer',filename) + if input.trace > 0 then + input.logger('= closer: %s, file: %s',tag,filename) + end input.show_close(filename) file_handle:close() end, @@ -5726,7 +6250,7 @@ if texconfig and not texlua then return t end - function input.openers.generic(instance,tag,filename) + function input.openers.generic(tag,filename) if filename and filename ~= "" then local f = io.open(filename,"r") if f then @@ -5734,16 +6258,20 @@ if texconfig and not texlua then return input.openers.text_opener(filename,f,tag) end end - input.logger('- ' .. tag .. ' opener',filename) + if input.trace > 0 then + input.logger('- opener: %s, file: %s',tag,filename) + end return unpack(input.openers.notfound) end - function input.loaders.generic(instance,tag,filename) + function input.loaders.generic(tag,filename) if filename and filename ~= "" then local f = io.open(filename,"rb") if f then input.show_load(filename) - input.logger('+ ' .. tag .. ' loader',filename) + if input.trace > 0 then + input.logger('+ loader: %s, file: %s',tag,filename) + end local s = f:read("*a") f:close() if s then @@ -5751,18 +6279,20 @@ if texconfig and not texlua then end end end - input.logger('- ' .. tag .. ' loader',filename) + if input.trace > 0 then + input.logger('- loader: %s, file: %s',tag,filename) + end return unpack(input.loaders.notfound) end - function input.finders.tex(instance,filename,filetype) - return input.finders.generic(instance,'tex',filename,filetype) + function input.finders.tex(filename,filetype) + return input.finders.generic('tex',filename,filetype) end - function input.openers.tex(instance,filename) - return input.openers.generic(instance,'tex',filename) + function input.openers.tex(filename) + return input.openers.generic('tex',filename) end - function input.loaders.tex(instance,filename) - return input.loaders.generic(instance,'tex',filename) + function input.loaders.tex(filename) + return input.loaders.generic('tex',filename) end end @@ -5778,13 +6308,13 @@ if texconfig and not texlua then do local ss = { } - function ctx.writestatus(a,b) + function ctx.writestatus(a,b,...) local s = ss[a] if not ss[a] then s = a:rpadd(15) .. ": " ss[a] = s end - texio.write_nl(s .. b .. "\n") + texio.write_nl(s .. format(b,...) .. "\n") end -- this will become: ctx.install_statistics(fnc() return ..,.. end) etc @@ -5797,62 +6327,69 @@ if texconfig and not texlua then do end function ctx.show_statistics() -- todo: move calls + local loadtime, register_statistics = input.loadtime, ctx.register_statistics if caches then - ctx.register_statistics("used config path", "%s", function() return caches.configpath(texmf.instance) end) - ctx.register_statistics("used cache path", "%s", function() return caches.path end) + register_statistics("used config path", "%s", function() return caches.configpath() end) + register_statistics("used cache path", "%s", function() return caches.temp() or "?" end) end if status.luabytecodes > 0 and input.storage and input.storage.done then - ctx.register_statistics("modules/dumps/instances", "%s/%s/%s", function() return status.luabytecodes-500, input.storage.done, status.luastates end) + register_statistics("modules/dumps/instances", "%s/%s/%s", function() return status.luabytecodes-500, input.storage.done, status.luastates end) end - if texmf.instance then - ctx.register_statistics("input load time", "%s seconds", function() return input.loadtime(texmf.instance) end) + if input.instance then + register_statistics("input load time", "%s seconds", function() return loadtime(input.instance) end) end if fonts then - ctx.register_statistics("fonts load time","%s seconds", function() return input.loadtime(fonts) end) + register_statistics("fonts load time","%s seconds", function() return loadtime(fonts) end) end if xml then - ctx.register_statistics("xml load time", "%s seconds, backreferences: %i, outer filtering time: %s", function() return input.loadtime(xml), #lxml.self, input.loadtime(lxml) end) + register_statistics("xml load time", "%s seconds, lpath calls: %s, cached calls: %s", function() + local stats = xml.statistics() + return loadtime(xml), stats.lpathcalls, stats.lpathcached + end) + register_statistics("lxml load time", "%s seconds preparation, backreferences: %i", function() + return loadtime(lxml), #lxml.self + end) end if mptopdf then - ctx.register_statistics("mps conversion time", "%s seconds", function() return input.loadtime(mptopdf) end) + register_statistics("mps conversion time", "%s seconds", function() return loadtime(mptopdf) end) end if nodes then - ctx.register_statistics("node processing time", "%s seconds (including kernel)", function() return input.loadtime(nodes) end) + register_statistics("node processing time", "%s seconds including kernel", function() return loadtime(nodes) end) end if kernel then - ctx.register_statistics("kernel processing time", "%s seconds", function() return input.loadtime(kernel) end) + register_statistics("kernel processing time", "%s seconds", function() return loadtime(kernel) end) end if attributes then - ctx.register_statistics("attribute processing time", "%s seconds", function() return input.loadtime(attributes) end) + register_statistics("attribute processing time", "%s seconds", function() return loadtime(attributes) end) end if languages then - ctx.register_statistics("language load time", "%s seconds, n=%s", function() return input.loadtime(languages), languages.hyphenation.n() end) + register_statistics("language load time", "%s seconds, n=%s", function() return loadtime(languages), languages.hyphenation.n() end) end if figures then - ctx.register_statistics("graphics processing time", "%s seconds, n=%s (including tex)", function() return input.loadtime(figures), figures.n or "?" end) + register_statistics("graphics processing time", "%s seconds including tex, n=%s", function() return loadtime(figures), figures.n or "?" end) end if metapost then - ctx.register_statistics("metapost processing time", "%s seconds, loading: %s seconds, execution: %s seconds, n: %s", function() return input.loadtime(metapost), input.loadtime(mplib), input.loadtime(metapost.exectime), metapost.n end) + register_statistics("metapost processing time", "%s seconds, loading: %s seconds, execution: %s seconds, n: %s", function() return loadtime(metapost), loadtime(mplib), loadtime(metapost.exectime), metapost.n end) end if status.luastate_bytes then - ctx.register_statistics("current memory usage", "%s bytes", function() return status.luastate_bytes end) + register_statistics("current memory usage", "%s bytes", function() return status.luastate_bytes end) end if nodes then - ctx.register_statistics("cleaned up reserved nodes", "%s nodes, %s lists of %s", function() return nodes.cleanup_reserved(tex.count[24]) end) -- \topofboxstack + register_statistics("cleaned up reserved nodes", "%s nodes, %s lists of %s", function() return nodes.cleanup_reserved(tex.count[24]) end) -- \topofboxstack end if status.node_mem_usage then - ctx.register_statistics("node memory usage", "%s", function() return status.node_mem_usage end) + register_statistics("node memory usage", "%s", function() return status.node_mem_usage end) end if languages then - ctx.register_statistics("loaded patterns", "%s", function() return languages.logger.report() end) + register_statistics("loaded patterns", "%s", function() return languages.logger.report() end) end if fonts then - ctx.register_statistics("loaded fonts", "%s", function() return fonts.logger.report() end) + register_statistics("loaded fonts", "%s", function() return fonts.logger.report() end) end if xml then -- so we are in mkiv, we need a different check - ctx.register_statistics("runtime", "%s seconds, %i processed pages, %i shipped pages, %.3f pages/second", function() - input.stoptiming(texmf) - local runtime = input.loadtime(texmf) + register_statistics("runtime", "%s seconds, %i processed pages, %i shipped pages, %.3f pages/second", function() + input.stoptiming(input.instance) + local runtime = loadtime(input.instance) local shipped = tex.count['nofshipouts'] local pages = tex.count['realpageno'] - 1 local persecond = shipped / runtime @@ -5861,8 +6398,8 @@ if texconfig and not texlua then do end for _, t in ipairs(statusinfo) do local tag, pattern, fnc = t[1], t[2], t[3] - ctx.writestatus("mkiv lua stats", string.format("%s - %s", tag:rpadd(n," "), pattern:format(fnc()))) - end + ctx.writestatus("mkiv lua stats", "%s - %s", tag:rpadd(n," "), pattern:format(fnc())) + end-- input.expanded_path_list("osfontdir") end end end @@ -5875,65 +6412,65 @@ if texconfig and not texlua then -- if still present, we overload kpse (put it off-line so to say) - if not texmf then texmf = { } end + input.starttiming(input.instance) - input.starttiming(texmf) + if not input.instance then - if not texmf.instance then + if not input.instance then -- prevent a second loading - if not texmf.instance then -- prevent a second loading + input.instance = input.reset() + input.instance.progname = 'context' + input.instance.engine = 'luatex' + input.instance.validfile = input.validctxfile - texmf.instance = input.reset() - texmf.instance.progname = environment.progname or 'context' - texmf.instance.engine = environment.engine or 'luatex' - texmf.instance.validfile = input.validctxfile - - input.load(texmf.instance) + input.load() end if callback then - callback.register('find_read_file' , function(id,name) return input.findtexfile(texmf.instance,name) end) - callback.register('open_read_file' , function( name) return input.opentexfile(texmf.instance,name) end) + callback.register('find_read_file' , function(id,name) return input.findtexfile(name) end) + callback.register('open_read_file' , function( name) return input.opentexfile(name) end) end if callback then - callback.register('find_data_file' , function(name) return input.findbinfile(texmf.instance,name,"tex") end) - callback.register('find_enc_file' , function(name) return input.findbinfile(texmf.instance,name,"enc") end) - callback.register('find_font_file' , function(name) return input.findbinfile(texmf.instance,name,"tfm") end) - callback.register('find_format_file' , function(name) return input.findbinfile(texmf.instance,name,"fmt") end) - callback.register('find_image_file' , function(name) return input.findbinfile(texmf.instance,name,"tex") end) - callback.register('find_map_file' , function(name) return input.findbinfile(texmf.instance,name,"map") end) - callback.register('find_ocp_file' , function(name) return input.findbinfile(texmf.instance,name,"ocp") end) - callback.register('find_opentype_file' , function(name) return input.findbinfile(texmf.instance,name,"otf") end) - callback.register('find_output_file' , function(name) return name end) - callback.register('find_pk_file' , function(name) return input.findbinfile(texmf.instance,name,"pk") end) - callback.register('find_sfd_file' , function(name) return input.findbinfile(texmf.instance,name,"sfd") end) - callback.register('find_truetype_file' , function(name) return input.findbinfile(texmf.instance,name,"ttf") end) - callback.register('find_type1_file' , function(name) return input.findbinfile(texmf.instance,name,"pfb") end) - callback.register('find_vf_file' , function(name) return input.findbinfile(texmf.instance,name,"vf") end) - - callback.register('read_data_file' , function(file) return input.loadbinfile(texmf.instance,file,"tex") end) - callback.register('read_enc_file' , function(file) return input.loadbinfile(texmf.instance,file,"enc") end) - callback.register('read_font_file' , function(file) return input.loadbinfile(texmf.instance,file,"tfm") end) + callback.register('find_data_file' , function(name) return input.findbinfile(name,"tex") end) + callback.register('find_enc_file' , function(name) return input.findbinfile(name,"enc") end) + callback.register('find_font_file' , function(name) return input.findbinfile(name,"tfm") end) + callback.register('find_format_file' , function(name) return input.findbinfile(name,"fmt") end) + callback.register('find_image_file' , function(name) return input.findbinfile(name,"tex") end) + callback.register('find_map_file' , function(name) return input.findbinfile(name,"map") end) + callback.register('find_ocp_file' , function(name) return input.findbinfile(name,"ocp") end) + callback.register('find_opentype_file' , function(name) return input.findbinfile(name,"otf") end) + callback.register('find_output_file' , function(name) return name end) + callback.register('find_pk_file' , function(name) return input.findbinfile(name,"pk") end) + callback.register('find_sfd_file' , function(name) return input.findbinfile(name,"sfd") end) + callback.register('find_truetype_file' , function(name) return input.findbinfile(name,"ttf") end) + callback.register('find_type1_file' , function(name) return input.findbinfile(name,"pfb") end) + callback.register('find_vf_file' , function(name) return input.findbinfile(name,"vf") end) + + callback.register('read_data_file' , function(file) return input.loadbinfile(file,"tex") end) + callback.register('read_enc_file' , function(file) return input.loadbinfile(file,"enc") end) + callback.register('read_font_file' , function(file) return input.loadbinfile(file,"tfm") end) -- format -- image - callback.register('read_map_file' , function(file) return input.loadbinfile(texmf.instance,file,"map") end) - callback.register('read_ocp_file' , function(file) return input.loadbinfile(texmf.instance,file,"ocp") end) - callback.register('read_opentype_file' , function(file) return input.loadbinfile(texmf.instance,file,"otf") end) + callback.register('read_map_file' , function(file) return input.loadbinfile(file,"map") end) + callback.register('read_ocp_file' , function(file) return input.loadbinfile(file,"ocp") end) + callback.register('read_opentype_file' , function(file) return input.loadbinfile(file,"otf") end) -- output - callback.register('read_pk_file' , function(file) return input.loadbinfile(texmf.instance,file,"pk") end) - callback.register('read_sfd_file' , function(file) return input.loadbinfile(texmf.instance,file,"sfd") end) - callback.register('read_truetype_file' , function(file) return input.loadbinfile(texmf.instance,file,"ttf") end) - callback.register('read_type1_file' , function(file) return input.loadbinfile(texmf.instance,file,"pfb") end) - callback.register('read_vf_file' , function(file) return input.loadbinfile(texmf.instance,file,"vf" ) end) + callback.register('read_pk_file' , function(file) return input.loadbinfile(file,"pk") end) + callback.register('read_sfd_file' , function(file) return input.loadbinfile(file,"sfd") end) + callback.register('read_truetype_file' , function(file) return input.loadbinfile(file,"ttf") end) + callback.register('read_type1_file' , function(file) return input.loadbinfile(file,"pfb") end) + callback.register('read_vf_file' , function(file) return input.loadbinfile(file,"vf" ) end) end - if callback and environment.aleph_mode then - callback.register('find_font_file' , function(name) return input.findbinfile(texmf.instance,name,"ofm") end) - callback.register('read_font_file' , function(file) return input.loadbinfile(texmf.instance,file,"ofm") end) - callback.register('find_vf_file' , function(name) return input.findbinfile(texmf.instance,name,"ovf") end) - callback.register('read_vf_file' , function(file) return input.loadbinfile(texmf.instance,file,"ovf") end) + if input.aleph_mode == nil then environment.aleph_mode = true end -- some day we will drop omega font support + + if callback and input.aleph_mode then + callback.register('find_font_file' , function(name) return input.findbinfile(name,"ofm") end) + callback.register('read_font_file' , function(file) return input.loadbinfile(file,"ofm") end) + callback.register('find_vf_file' , function(name) return input.findbinfile(name,"ovf") end) + callback.register('read_vf_file' , function(file) return input.loadbinfile(file,"ovf") end) end if callback then @@ -6021,16 +6558,16 @@ if texconfig and not texlua then if kpse then function kpse.find_file(filename,filetype,mustexist) - return input.find_file(texmf.instance,filename,filetype,mustexist) + return input.find_file(filename,filetype,mustexist) end function kpse.expand_path(variable) - return input.expand_path(texmf.instance,variable) + return input.expand_path(variable) end function kpse.expand_var(variable) - return input.expand_var(texmf.instance,variable) + return input.expand_var(variable) end function kpse.expand_braces(variable) - return input.expand_braces(texmf.instance,variable) + return input.expand_braces(variable) end end @@ -6057,7 +6594,7 @@ if texconfig and not texlua then function luatex.variables() local t, x = { }, nil for _,v in pairs(luatex.variablenames) do - x = input.var_value(texmf.instance,v) + x = input.var_value(v) if x and x:find("^%d+$") then t[v] = tonumber(x) end @@ -6081,28 +6618,34 @@ if texconfig and not texlua then end --- some tex basics +-- some tex basics, maybe this will move to ctx -if not cs then cs = { } end +if tex then -function cs.def(k,v) - tex.sprint(tex.texcatcodes, "\\def\\" .. k .. "{" .. v .. "}") -end + local texsprint, texwrite = tex.sprint, tex.write -function cs.chardef(k,v) - tex.sprint(tex.texcatcodes, "\\chardef\\" .. k .. "=" .. v .. "\\relax") -end + if not cs then cs = { } end -function cs.boolcase(b) - if b then tex.write(1) else tex.write(0) end -end + function cs.def(k,v) + texsprint(tex.texcatcodes, "\\def\\" .. k .. "{" .. v .. "}") + end -function cs.testcase(b) - if b then - tex.sprint(tex.texcatcodes, "\\firstoftwoarguments") - else - tex.sprint(tex.texcatcodes, "\\secondoftwoarguments") + function cs.chardef(k,v) + texsprint(tex.texcatcodes, "\\chardef\\" .. k .. "=" .. v .. "\\relax") end + + function cs.boolcase(b) + if b then texwrite(1) else texwrite(0) end + end + + function cs.testcase(b) + if b then + texsprint(tex.texcatcodes, "\\firstoftwoarguments") + else + texsprint(tex.texcatcodes, "\\secondoftwoarguments") + end + end + end @@ -6235,6 +6778,7 @@ own.libs = { -- todo: check which ones are really needed 'l-utils.lua', 'luat-lib.lua', 'luat-inp.lua', + 'luat-log.lua', 'luat-tmp.lua', 'luat-zip.lua', 'luat-tex.lua', @@ -6288,19 +6832,21 @@ if not input then os.exit() end -instance = input.reset() +input.instance = input.reset() input.verbose = environment.arguments["verbose"] or false -input.banner = 'LuaTools | ' +input.banner = 'LuaTools' utils.report = input.report input.defaultlibs = { -- not all are needed 'l-string.lua', 'l-lpeg.lua', 'l-table.lua', 'l-boolean.lua', 'l-number.lua', 'l-set.lua', 'l-unicode.lua', - 'l-md5.lua', 'l-os.lua', 'l-io.lua', 'l-file.lua', 'l-url.lua', 'l-dir.lua', 'l-utils.lua', 'l-tex.lua', - 'luat-env.lua', 'luat-lib.lua', 'luat-inp.lua', 'luat-tmp.lua', 'luat-zip.lua', 'luat-tex.lua' + 'l-md5.lua', 'l-os.lua', 'l-io.lua', 'l-file.lua', 'l-url.lua', 'l-dir.lua', 'l-utils.lua', 'l-dimen.lua', + 'luat-lib.lua', 'luat-inp.lua', 'luat-env.lua', 'luat-tmp.lua', 'luat-zip.lua', 'luat-tex.lua' } -- todo: use environment.argument() instead of environment.arguments[] +local instance = input.instance + instance.engine = environment.arguments["engine"] or 'luatex' instance.progname = environment.arguments["progname"] or 'context' instance.luaname = environment.arguments["luafile"] or "" -- environment.ownname or "" @@ -6325,19 +6871,19 @@ if environment.arguments["minimize"] then end 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) +function input.my_prepare_a() + input.resetconfig() + input.identify_cnf() + input.load_lua() + input.expand_variables() + input.load_cnf() + input.expand_variables() end -function input.my_prepare_b(instance) - input.my_prepare_a(instance) - input.load_hash(instance) - input.automount(instance) +function input.my_prepare_b() + input.my_prepare_a() + input.load_hash() + input.automount() end -- barename @@ -6379,10 +6925,11 @@ messages.help = [[ --lsr use lsr and cnf directly ]] -function input.my_make_format(instance,texname) +function input.my_make_format(texname) + local instance = input.instance if texname and texname ~= "" then if input.usecache then - local path = file.join(caches.setpath(instance,"formats")) -- maybe platform + local path = file.join(caches.setpath("formats")) -- maybe platform if path and lfs then lfs.chdir(path) end @@ -6391,22 +6938,22 @@ function input.my_make_format(instance,texname) if barename == texname then texname = texname .. ".tex" end - local fullname = input.find_files(instance,texname)[1] or "" + local fullname = input.find_files(texname)[1] or "" if fullname == "" then - input.report("no tex file with name",texname) + input.report("no tex file with name: %s",texname) else local luaname, lucname, luapath, lualibs = "", "", "", { } -- the following is optional, since context.lua can also -- handle this collect and compile business if environment.arguments["compile"] then if luaname == "" then luaname = barename end - input.report("creating initialization file " .. luaname) + input.report("creating initialization file: %s",luaname) luapath = file.dirname(luaname) if luapath == "" then luapath = file.dirname(texname) end if luapath == "" then - luapath = file.dirname(input.find_files(instance,texname)[1] or "") + luapath = file.dirname(input.find_files(texname)[1] or "") end lualibs = string.split(instance.lualibs,",") luaname = file.basename(barename .. ".lua") @@ -6416,27 +6963,28 @@ function input.my_make_format(instance,texname) if lualibs[1] then local firstlib = file.join(luapath,lualibs[1]) if not lfs.isfile(firstlib) then - local foundname = input.find_files(instance,lualibs[1])[1] + local foundname = input.find_files(lualibs[1])[1] if foundname then - input.report("located library path : " .. luapath) + input.report("located library path: %s",luapath) luapath = file.dirname(foundname) end end end - input.report("using library path : " .. luapath) - input.report("using lua libraries: " .. table.join(lualibs," ")) + input.report("using library path: %s",luapath) + input.report("using lua libraries: %s",table.join(lualibs," ")) utils.merger.selfcreate(lualibs,luapath,luaname) - if utils.lua.compile(luaname, lucname) and io.exists(lucname) then + local strip = input.boolean_variable("LUACSTRIP", true) + if utils.lua.compile(luaname,lucname,false,strip) and io.exists(lucname) then luaname = lucname - input.report("using compiled initialization file " .. lucname) + input.report("using compiled initialization file: %s",lucname) else - input.report("using uncompiled initialization file " .. luaname) + input.report("using uncompiled initialization file: %s",luaname) end else for _, v in pairs({instance.luaname, instance.progname, barename}) do v = string.gsub(v..".lua","%.lua%.lua$",".lua") if v and (v ~= "") then - luaname = input.find_files(instance,v)[1] or "" + luaname = input.find_files(v)[1] or "" if luaname ~= "" then break end @@ -6445,22 +6993,30 @@ function input.my_make_format(instance,texname) end if luaname == "" then input.reportlines(messages.no_ini_file) - input.report("texname : " .. texname) - input.report("luaname : " .. instance.luaname) - input.report("progname : " .. instance.progname) - input.report("barename : " .. barename) + input.report("texname : %s",texname) + input.report("luaname : %s",instance.luaname) + input.report("progname: %s",instance.progname) + input.report("barename: %s",barename) else - input.report("using lua initialization file " .. luaname) + input.report("using lua initialization file: %s",luaname) + local mp = dir.glob(file.stripsuffix(file.basename(luaname)).."-*.mem") + if mp and #mp > 0 then + for _, name in ipairs(mp) do + input.report("removing related mplib format %s", file.basename(name)) + os.remove(name) + end + end local flags = { "--ini" } if environment.arguments["mkii"] then flags[#flags+1] = "--progname=" .. instance.progname else flags[#flags+1] = "--lua=" .. string.quote(luaname) end - local bs = (environment.platform == "unix" and "\\\\") or "\\" -- todo: make a function + local bs = (os.platform == "unix" and "\\\\") or "\\" -- todo: make a function local command = "luatex ".. table.concat(flags," ") .. " " .. string.quote(fullname) .. " " .. bs .. "dump" - input.report("running command: " .. command .. "\n") + input.report("running command: %s\n",command) os.spawn(command) + -- todo: do a dummy run that generates the related metafun and mfplain formats end end else @@ -6468,22 +7024,22 @@ function input.my_make_format(instance,texname) end end -function input.my_run_format(instance,name,data,more) +function input.my_run_format(name,data,more) -- hm, rather old code here; we can now use the file.whatever functions if name and (name ~= "") then local barename = name:gsub("%.%a+$","") local fmtname = "" if input.usecache then - local path = file.join(caches.setpath(instance,"formats")) -- maybe platform + local path = file.join(caches.setpath("formats")) -- maybe platform fmtname = file.join(path,barename..".fmt") or "" end if fmtname == "" then - fmtname = input.find_files(instance,barename..".fmt")[1] or "" + fmtname = input.find_files(barename..".fmt")[1] or "" end fmtname = input.clean_path(fmtname) barename = fmtname:gsub("%.%a+$","") if fmtname == "" then - input.report("no format with name",name) + input.report("no format with name: %s",name) else local luaname = barename .. ".luc" local f = io.open(luaname) @@ -6494,11 +7050,11 @@ function input.my_run_format(instance,name,data,more) if f then f:close() local command = "luatex --fmt=" .. string.quote(barename) .. " --lua=" .. string.quote(luaname) .. " " .. string.quote(data) .. " " .. string.quote(more) - input.report("running command: " .. command) + input.report("running command: %s",command) os.spawn(command) else - input.report("using format name",fmtname) - input.report("no luc/lua with name",barename) + input.report("using format name: %s",fmtname) + input.report("no luc/lua with name: %s",barename) end end end @@ -6516,8 +7072,9 @@ local function tabstr(str) end end -local function list(instance,list) - local pat = string.upper(instance.pattern or "","") +local function list(list) + local instance = input.instance + local pat = string.upper(pattern or "","") for _,key in pairs(table.sortedkeys(list)) do if instance.pattern == "" or string.find(key:upper(),pat) then if instance.kpseonly then @@ -6531,10 +7088,11 @@ local function list(instance,list) 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.variables () list(input.instance.variables ) end +function input.listers.expansions() list(input.instance.expansions) end -function input.listers.configurations(instance) +function input.listers.configurations() + local instance = input.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") @@ -6549,61 +7107,58 @@ function input.listers.configurations(instance) end end -input.report(banner,"\n") +input.report("%s\n",banner) local ok = true if environment.arguments["find-file"] then - input.my_prepare_b(instance) + input.my_prepare_b() instance.format = environment.arguments["format"] or instance.format if instance.pattern then instance.allresults = true - input.for_files(instance, input.find_files, { instance.pattern }, instance.my_format) + input.for_files(input.find_files, { instance.pattern }, instance.my_format) else - input.for_files(instance, input.find_files, environment.files, instance.my_format) + input.for_files(input.find_files, environment.files, instance.my_format) end elseif environment.arguments["find-path"] then - input.my_prepare_b(instance) - local path = input.find_file(instance, environment.files[1], instance.my_format) + input.my_prepare_b() + local path = input.find_file(environment.files[1], instance.my_format) if input.verbose then input.report(file.dirname(path)) else print(file.dirname(path)) end ---~ elseif environment.arguments["first-writable-path"] then ---~ input.my_prepare_b(instance) ---~ input.report(input.first_writable_path(instance,environment.files[1] or ".")) elseif environment.arguments["run"] then - input.my_prepare_a(instance) -- ! no need for loading databases + input.my_prepare_a() -- ! no need for loading databases input.verbose = true - input.my_run_format(instance,environment.files[1] or "",environment.files[2] or "",environment.files[3] or "") + input.my_run_format(environment.files[1] or "",environment.files[2] or "",environment.files[3] or "") elseif environment.arguments["fmt"] then - input.my_prepare_a(instance) -- ! no need for loading databases + input.my_prepare_a() -- ! no need for loading databases input.verbose = true - input.my_run_format(instance,environment.arguments["fmt"], environment.files[1] or "",environment.files[2] or "") + input.my_run_format(environment.arguments["fmt"], environment.files[1] or "",environment.files[2] or "") elseif environment.arguments["expand-braces"] then - input.my_prepare_a(instance) - input.for_files(instance, input.expand_braces, environment.files) + input.my_prepare_a() + input.for_files(input.expand_braces, environment.files) elseif environment.arguments["expand-path"] then - input.my_prepare_a(instance) - input.for_files(instance, input.expand_path, environment.files) + input.my_prepare_a() + input.for_files(input.expand_path, environment.files) elseif environment.arguments["expand-var"] or environment.arguments["expand-variable"] then - input.my_prepare_a(instance) - input.for_files(instance, input.expand_var, environment.files) + input.my_prepare_a() + input.for_files(input.expand_var, environment.files) elseif environment.arguments["show-path"] or environment.arguments["path-value"] then - input.my_prepare_a(instance) - input.for_files(instance, input.show_path, environment.files) + input.my_prepare_a() + input.for_files(input.show_path, environment.files) elseif environment.arguments["var-value"] or environment.arguments["show-value"] then - input.my_prepare_a(instance) - input.for_files(instance, input.var_value, environment.files) + input.my_prepare_a() + input.for_files(input.var_value, environment.files) elseif environment.arguments["format-path"] then - input.my_prepare_b(instance) - input.report(caches.setpath(instance,"format")) + input.my_prepare_b() + input.report(caches.setpath("format")) elseif instance.pattern then -- brrr - input.my_prepare_b(instance) + input.my_prepare_b() instance.format = environment.arguments["format"] or instance.format instance.allresults = true - input.for_files(instance, input.find_files, { instance.pattern }, instance.my_format) + input.for_files(input.find_files, { instance.pattern }, instance.my_format) elseif environment.arguments["generate"] then instance.renewcache = true input.verbose = true @@ -6611,46 +7166,42 @@ elseif environment.arguments["generate"] then elseif environment.arguments["make"] or environment.arguments["ini"] or environment.arguments["compile"] then input.my_prepare_b(instance) input.verbose = true - input.my_make_format(instance,environment.files[1] or "") + input.my_make_format(environment.files[1] or "") elseif environment.arguments["selfmerge"] then utils.merger.selfmerge(own.name,own.libs,own.list) elseif environment.arguments["selfclean"] then utils.merger.selfclean(own.name) elseif environment.arguments["selfupdate"] then - input.my_prepare_b(instance) + input.my_prepare_b() input.verbose = true - input.update_script(instance,own.name,"luatools") + input.update_script(own.name,"luatools") elseif environment.arguments["variables"] or environment.arguments["show-variables"] then - input.my_prepare_a(instance) - input.listers.variables(instance) + input.my_prepare_a() + input.listers.variables() elseif environment.arguments["expansions"] or environment.arguments["show-expansions"] then - input.my_prepare_a(instance) - input.listers.expansions(instance) + input.my_prepare_a() + input.listers.expansions() elseif environment.arguments["configurations"] or environment.arguments["show-configurations"] then - input.my_prepare_a(instance) - input.listers.configurations(instance) + input.my_prepare_a() + input.listers.configurations() elseif environment.arguments["help"] or (environment.files[1]=='help') or (#environment.files==0) then if not input.verbose then input.verbose = true - input.report(banner,"\n") + input.report("%s\n",banner) end - input.reportlines(messages.help) + input.reportlines(messages.help) -- input.help ? else - input.my_prepare_b(instance) - input.for_files(instance, input.find_files, environment.files, instance.my_format) + input.my_prepare_b() + input.for_files(input.find_files, environment.files, instance.my_format) end if input.verbose then input.report("") - input.report(string.format("runtime: %0.3f seconds",os.runtime())) + input.report("runtime: %0.3f seconds",os.runtime()) end ---~ if ok then ---~ input.report("exit code: 0") os.exit(0) ---~ else ---~ input.report("exit code: 1") os.exit(1) ---~ end - -if environment.platform == "unix" then +if os.platform == "unix" then io.write("\n") end + + diff --git a/scripts/context/lua/mtx-babel.lua b/scripts/context/lua/mtx-babel.lua index c9855b86a..44254352c 100644 --- a/scripts/context/lua/mtx-babel.lua +++ b/scripts/context/lua/mtx-babel.lua @@ -8,8 +8,6 @@ if not modules then modules = { } end modules ['mtx-babel'] = { -- data tables by Thomas A. Schmitz -texmf.instance = instance -- we need to get rid of this / maybe current instance in global table - scripts = scripts or { } scripts.babel = scripts.babel or { } @@ -384,22 +382,22 @@ do local structure = environment.argument("structure") or "document" converter = converter[structure] if converter then - input.report(string.format("converting '%s' using language '%s' with structure '%s'", filename, language, structure)) + input.report("converting '%s' using language '%s' with structure '%s'", filename, language, structure) data = converter:match(data) local newfilename = filename .. ".utf" io.savedata(newfilename, data) - input.report(string.format("converted data saved in '%s'", newfilename)) + input.report("converted data saved in '%s'", newfilename) else - input.report(string.format("unknown structure '%s' language '%s'", structure, language)) + input.report("unknown structure '%s' language '%s'", structure, language) end else - input.report(string.format("no converter for language '%s'", language)) + input.report("no converter for language '%s'", language) end else - input.report(string.format("provide language")) + input.report("provide language") end else - input.report(string.format("no data in '%s'",filename)) + input.report("no data in '%s'",filename) end end end @@ -427,4 +425,3 @@ if environment.argument("convert") then else input.help(banner,messages.help) end - diff --git a/scripts/context/lua/mtx-cache.lua b/scripts/context/lua/mtx-cache.lua index 8091eaa65..0432168ee 100644 --- a/scripts/context/lua/mtx-cache.lua +++ b/scripts/context/lua/mtx-cache.lua @@ -6,20 +6,18 @@ if not modules then modules = { } end modules ['mtx-cache'] = { license = "see context related readme files" } -texmf.instance = instance -- we need to get rid of this / maybe current instance in global table - scripts = scripts or { } scripts.cache = scripts.cache or { } function scripts.cache.collect_one(...) - local path = caches.setpath(instance,...) + local path = caches.setpath(...) local tmas = dir.glob(path .. "/*.tma") local tmcs = dir.glob(path .. "/*.tmc") return path, tmas, tmcs end function scripts.cache.collect_two(...) - local path = caches.setpath(instance,...) + local path = caches.setpath(...) local rest = dir.glob(path .. "/**/*") return path, rest end diff --git a/scripts/context/lua/mtx-chars.lua b/scripts/context/lua/mtx-chars.lua index a05ab9f08..f4f751377 100644 --- a/scripts/context/lua/mtx-chars.lua +++ b/scripts/context/lua/mtx-chars.lua @@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['mtx-chars'] = { license = "see context related readme files" } -texmf.instance = instance -- we need to get rid of this / maybe current instance in global table +local format, concat = string.format, table.concat scripts = scripts or { } scripts.chars = scripts.chars or { } @@ -35,7 +35,6 @@ function scripts.chars.stixtomkiv(inname,outname) C = "closing", F = "fence" } - local format, concat = string.format, table.concat local valid, done = false, { } local g = io.open(outname,'w') g:write([[ @@ -81,7 +80,44 @@ if not characters then characters = { } end end end -scripts.chars.banner_utf_1 = [[ +local banner_pdf_1 = [[ +% filename : pdfr-def.tex +% comment : generated by mtxrun --script chars --pdf +% author : Hans Hagen, PRAGMA-ADE, Hasselt NL +% copyright: PRAGMA ADE / ConTeXt Development Team +% license : see context related readme files +% +]] + +local banner_pdf_2 = [[ +% +\endinput +]] + +function scripts.chars.makepdfr() + local chartable = input.find_file("char-def.lua") or "" + if chartable ~= "" then + dofile(chartable) + if characters and characters.data then + local f = io.open("pdfr-def.tex", 'w') + if f then + f:write(banner_pdf_1) + local cd = characters.data + local sd = table.sortedkeys(cd) + for i=1,#sd do + local char = cd[sd[i]] + if char.adobename then + f:write(format("\\pdfglyphtounicode{%s}{%04X}%%\n",char.adobename,char.unicodeslot)) + end + end + f:write(banner_pdf_2) + f:close() + end + end + end +end + +local banner_utf_1 = [[ % filename : enco-utf.tex % comment : generated by mtxrun --script chars --utf % author : Hans Hagen, PRAGMA-ADE, Hasselt NL @@ -98,33 +134,32 @@ scripts.chars.banner_utf_1 = [[ \fi ]] -scripts.chars.banner_utf_2 = [[ +local banner_utf_2 = [[ % lc/uc/catcode mappings ]] -scripts.chars.banner_utf_3 = [[ +local banner_utf_3 = [[ % named characters mapped onto utf (\\char is needed for accents) ]] -scripts.chars.banner_utf_4 = [[ +local banner_utf_4 = [[ \endinput ]] function scripts.chars.makeencoutf() - local chartable = input.find_file(instance,"char-def.lua") or "" + local chartable = input.find_file("char-def.lua") or "" if chartable ~= "" then dofile(chartable) if characters and characters.data then local f = io.open("enco-utf.tex", 'w') if f then - local char, format = unicode.utf8.char, string.format - f:write(scripts.chars.banner_utf_1) - f:write(scripts.chars.banner_utf_2) + f:write(banner_utf_1) + f:write(banner_utf_2) local list = table.sortedkeys(characters.data) local length = 0 for i=1,#list do @@ -142,7 +177,7 @@ function scripts.chars.makeencoutf() end end end - f:write(scripts.chars.banner_utf_3) + f:write(banner_utf_3) for i=1,#list do local code = list[i] if code > 0x5B and code <= 0xFFFF then @@ -157,7 +192,7 @@ function scripts.chars.makeencoutf() end end end - f:write(scripts.chars.banner_utf_4) + f:write(banner_utf_4) f:close() end end @@ -169,6 +204,7 @@ banner = banner .. " | character tools " messages.help = [[ --stix convert stix table to math table --utf generate enco-utf.tex (used by xetex) +--pdf generate pdfr-def.tex (used by pdftex) ]] if environment.argument("stix") then @@ -177,6 +213,8 @@ if environment.argument("stix") then scripts.chars.stixtomkiv(inname,outname) elseif environment.argument("utf") then scripts.chars.makeencoutf() +elseif environment.argument("pdf") then + scripts.chars.makepdfr() else input.help(banner,messages.help) end diff --git a/scripts/context/lua/mtx-check.lua b/scripts/context/lua/mtx-check.lua index dd8a71264..7c44fa855 100644 --- a/scripts/context/lua/mtx-check.lua +++ b/scripts/context/lua/mtx-check.lua @@ -6,8 +6,6 @@ if not modules then modules = { } end modules ['mtx-check'] = { license = "see context related readme files" } -texmf.instance = instance -- we need to get rid of this / maybe current instance in global table - scripts = scripts or { } scripts.checker = scripts.checker or { } diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua index 6c444d531..d90da11e0 100644 --- a/scripts/context/lua/mtx-context.lua +++ b/scripts/context/lua/mtx-context.lua @@ -6,8 +6,6 @@ if not modules then modules = { } end modules ['mtx-context'] = { license = "see context related readme files" } -texmf.instance = instance -- we need to get rid of this / maybe current instance in global table - scripts = scripts or { } scripts.context = scripts.context or { } @@ -30,11 +28,11 @@ end function input.locate_format(name) -- move this to core / luat-xxx local barename, fmtname = name:gsub("%.%a+$",""), "" if input.usecache then - local path = file.join(caches.setpath(instance,"formats")) -- maybe platform + local path = file.join(caches.setpath("formats")) -- maybe platform fmtname = file.join(path,barename..".fmt") or "" end if fmtname == "" then - fmtname = input.find_files(instance,barename..".fmt")[1] or "" + fmtname = input.find_files(barename..".fmt")[1] or "" end fmtname = input.clean_path(fmtname) if fmtname ~= "" then @@ -137,7 +135,7 @@ do elseif ctxdata.ctxname then ctlname = file.replacesuffix(ctxdata.ctxname,'ctl') else - input.report(string.format("invalid ctl name %s",ctlname or "?")) + input.report("invalid ctl name: %s",ctlname or "?") return end end @@ -145,7 +143,7 @@ do input.report("nothing prepared, no ctl file saved") os.remove(ctlname) else - input.report(string.format("saving logdata in %s",ctlname)) + input.report("saving logdata in: %s",ctlname) f = io.open(ctlname,'w') if f then f:write("<?xml version='1.0' standalone='yes'?>\n\n") @@ -190,8 +188,8 @@ do ctxdata.jobname = file.addsuffix(ctxdata.jobname,'tex') ctxdata.ctxname = file.addsuffix(ctxdata.ctxname,'ctx') - input.report("jobname:",ctxdata.jobname) - input.report("ctxname:",ctxdata.ctxname) + input.report("jobname: %s",ctxdata.jobname) + input.report("ctxname: %s",ctxdata.ctxname) -- mtxrun should resolve kpse: and file: @@ -238,17 +236,9 @@ do ctxdata.flags = ctxrunner.reflag(ctxdata.flags) for _, message in ipairs(ctxdata.messages) do - -- message ctxdata.justtext(xml.tostring(message)) + input.report("ctx comment: %s", xml.tostring(message)) end - --~ REXML::XPath.each(root,"//ctx:block") do |blk| - --~ if @jobname && blk.attributes['pattern'] then - --~ root.delete(blk) unless @jobname =~ /#{blk.attributes['pattern']}/ - --~ else - --~ root.delete(blk) - --~ end - --~ end - xml.each(ctxdata.xmldata,"ctx:value[@name='job']", function(ek,e,k) e[k] = ctxdata.variables['job'] or "" end) @@ -259,8 +249,8 @@ do commands[ek.at and ek.at['name'] or "unknown"] = ek end) - local suffix = xml.first(ctxdata.xmldata,"/ctx:job/ctx:preprocess/@suffix") or ctxdata.suffix - local runlocal = xml.first(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:processors/@local") + local suffix = xml.filter(ctxdata.xmldata,"/ctx:job/ctx:preprocess/attribute(suffix)") or ctxdata.suffix + local runlocal = xml.filter(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:processors/attribute(local)") runlocal = toboolean(runlocal) @@ -283,6 +273,7 @@ do pattern = ctxrunner.justtext(xml.tostring(pattern)) local oldfiles = dir.glob(pattern) + local pluspath = false if #oldfiles == 0 then -- message: no files match pattern @@ -333,11 +324,12 @@ do end end) -- potential optimization: when mtxrun run internal + command = xml.text(command) command = ctxrunner.justtext(command) -- command is still xml element here - input.report("command",command) - local result = os.spawn(command) + input.report("command: %s",command) + local result = os.spawn(command) or 0 if result > 0 then - input.report("error, return code",result) + input.report("error, return code: %s",result) end if ctxdata.runlocal then oldfile = file.basename(oldfile) @@ -348,7 +340,7 @@ do file.syncmtimes(oldfile,newfile) ctxdata.prepfiles[oldfile] = true else - input.report("error, check target location of new file", newfile) + input.report("error, check target location of new file: %s", newfile) ctxdata.prepfiles[oldfile] = false end else @@ -400,15 +392,13 @@ scripts.context.backends = { dvips = 'dvips' } -function scripts.context.multipass.makeoptionfile(jobname,ctxdata) +function scripts.context.multipass.makeoptionfile(jobname,ctxdata,kindofrun,currentrun,finalrun) -- take jobname from ctx local f = io.open(jobname..".top","w") if f then - local finalrun, kindofrun, currentrun = false, 0, 0 local function someflag(flag) return (ctxdata and ctxdata.flags[flag]) or environment.argument(flag) end ---~ local someflag = environment.argument local function setvalue(flag,format,hash,default) local a = someflag(flag) or default if a and a ~= "" then @@ -445,21 +435,23 @@ function scripts.context.multipass.makeoptionfile(jobname,ctxdata) end setalways("\\unprotect") setvalue('output' , "\\setupoutput[%s]", scripts.context.backends, 'pdftex') - setalways( "\\setupsystem[\\c!n=%s,\\c!m=%s]", kindofrun, currentrun) + setalways( "\\setupsystem[\\c!n=%s,\\c!m=%s]", kindofrun or 0, currentrun or 0) setalways( "\\setupsystem[\\c!type=%s]",os.platform) setfixed ("batchmode" , "\\batchmode") setfixed ("nonstopmode" , "\\nonstopmode") setfixed ("tracefiles" , "\\tracefilestrue") setfixed ("paranoid" , "\\def\\maxreadlevel{1}") setvalues("modefile" , "\\readlocfile{%s}{}{}") + setvalue ("inputfile" , "\\setupsystem[inputfile=%s]") setvalue ("result" , "\\setupsystem[file=%s]") setvalues("path" , "\\usepath[%s]") setfixed ("color" , "\\setupcolors[\\c!state=\\v!start]") - setfixed ("nompmode" , "\\runMPgraphicsfalse") -- obsolete, we assume runtime mp graphics - setfixed ("nomprun" , "\\runMPgraphicsfalse") -- obsolete, we assume runtime mp graphics - setfixed ("automprun" , "\\runMPgraphicsfalse") -- obsolete, we assume runtime mp graphics + -- setfixed ("nompmode" , "\\runMPgraphicsfalse") -- obsolete, we assume runtime mp graphics + -- setfixed ("nomprun" , "\\runMPgraphicsfalse") -- obsolete, we assume runtime mp graphics + -- setfixed ("automprun" , "\\runMPgraphicsfalse") -- obsolete, we assume runtime mp graphics setfixed ("fast" , "\\fastmode\n") setfixed ("silentmode" , "\\silentmode\n") + setfixed ("nostats" , "\\nomkivstatistics\n") setvalue ("separation" , "\\setupcolors[\\c!split=%s]") setvalue ("setuppath" , "\\setupsystem[\\c!directory={%s}]") setfixed ("noarrange" , "\\setuparranging[\\v!disable]") @@ -468,7 +460,7 @@ function scripts.context.multipass.makeoptionfile(jobname,ctxdata) end setvalue ("arguments" , "\\setupenv[%s]") setvalue ("randomseed" , "\\setupsystem[\\c!random=%s]") - setvalues("modes" , "\\enablemode[%s]") +--~ setvalues("modes" , "\\enablemode[%s]") setvalues("mode" , "\\enablemode[%s]") setvalues("filters" , "\\useXMLfilter[%s]") setvalues("usemodules" , "\\usemodule[%s]") @@ -480,8 +472,8 @@ function scripts.context.multipass.makeoptionfile(jobname,ctxdata) setvalues(ctxdata.environments, "\\environment %s ") end -- done - setalways( "\\protect") - setalways( "\\endinput") + setalways("\\protect") + setalways("\\endinput") f:close() end end @@ -509,6 +501,13 @@ scripts.context.xmlsuffixes = table.tohash { "xml", } +scripts.context.beforesuffixes = { + "tuo", "tuc" +} +scripts.context.aftersuffixes = { + "pdf", "tuo", "tuc", "log" +} + function scripts.context.run(ctxdata) local function makestub(format,filename) local stubname = file.replacesuffix(file.basename(filename),'run') @@ -530,9 +529,9 @@ function scripts.context.run(ctxdata) end local files = environment.files if #files > 0 then - input.identify_cnf(instance) - input.load_cnf(instance) - input.expand_variables(instance) + input.identify_cnf() + input.load_cnf() + input.expand_variables() local formatname = "cont-en" local formatfile, scriptfile = input.locate_format(formatname) if formatfile and scriptfile then @@ -542,26 +541,59 @@ function scripts.context.run(ctxdata) if pathname == "" then filename = "./" .. filename end - -- also other stubs - if environment.argument("forcexml") or scripts.context.xmlsuffixes[file.extname(filename) or "?"] then -- mkii - filename = makestub("\\processXMLfilegrouped{%s}",filename) - elseif environment.argument("processxml") then -- mkiv - filename = makestub("\\xmlprocess{%s}",filename) + -- we default to mkiv xml ! + if scripts.context.xmlsuffixes[file.extname(filename) or "?"] or environment.argument("forcexml") then + if environment.argument("mkii") then + filename = makestub("\\processXMLfilegrouped{%s}",filename) + else + filename = makestub("\\xmlprocess{\\xmldocument}{%s}{}",filename) + end + end + -- + -- todo: also other stubs + -- + local resultname, oldbase, newbase = environment.argument("result"), "", "" + if type(resultname) == "string" then + oldbase = file.removesuffix(jobname) + newbase = file.removesuffix(resultname) + if oldbase ~= newbase then + for _, suffix in pairs(scripts.context.beforesuffixes) do + local oldname = file.addsuffix(oldbase,suffix) + local newname = file.addsuffix(newbase,suffix) + os.remove(oldname) + os.rename(newname,oldname) + end + else + resultname = nil + end + else + resultname = nil end -- if environment.argument("autopdf") then os.spawn(string.format('pdfclose --file "%s" 2>&1', file.replacesuffix(filename,"pdf"))) + if resultname then + os.spawn(string.format('pdfclose --file "%s" 2>&1', file.replacesuffix(resultname,"pdf"))) + end end -- local command = "luatex --fmt=" .. string.quote(formatfile) .. " --lua=" .. string.quote(scriptfile) .. " " .. string.quote(filename) local oldhash, newhash = scripts.context.multipass.hashfiles(jobname), { } - scripts.context.multipass.makeoptionfile(jobname,ctxdata) - for i=1, scripts.context.multipass.nofruns do - input.report(string.format("run %s: %s",i,command)) - local returncode = os.spawn(command) - input.report("return code: " .. returncode) - if returncode > 0 then - input.report("fatal error, run aborted") + local once = environment.argument("once") + local maxnofruns = (once and 1) or scripts.context.multipass.nofruns + for i=1,maxnofruns do + -- 1:first run, 2:successive run, 3:once, 4:last of maxruns + local kindofrun = (once and 3) or (i==1 and 1) or (i==maxnofruns and 4) or 2 + scripts.context.multipass.makeoptionfile(jobname,ctxdata,kindofrun,i,false) -- kindofrun, currentrun, final + input.report("run %s: %s",i,command) + local returncode, errorstring = os.spawn(command) + if not returncode then + input.report("fatal error, message: %s",errorstring or "?") + os.exit(1) + break + elseif returncode > 0 then + input.report("fatal error, code: %s",returncode or "?") + os.exit(returncode) break else scripts.context.multipass.copyluafile(jobname) @@ -575,25 +607,63 @@ function scripts.context.run(ctxdata) end end -- - -- todo: result + -- todo: extra arrange run + -- + if environment.argument("purge") then + scripts.context.purge_job(filename) + elseif environment.argument("purgeall") then + scripts.context.purge_job(filename,true) + end -- + if resultname then + for _, suffix in pairs(scripts.context.aftersuffixes) do + local oldname = file.addsuffix(oldbase,suffix) + local newname = file.addsuffix(newbase,suffix) + os.remove(newname) + os.rename(oldname,newname) + end + input.report("result renamed to: %s",newbase) + end if environment.argument("autopdf") then - os.spawn(string.format('pdfopen --file "%s" 2>&1', file.replacesuffix(filename,"pdf"))) + if resultname then + os.spawn(string.format('pdfopen --file "%s" 2>&1', file.replacesuffix(resultname,"pdf"))) + else + os.spawn(string.format('pdfopen --file "%s" 2>&1', file.replacesuffix(filename,"pdf"))) + end end -- end else input.verbose = true - input.report("error", "no format found with name " .. formatname) + input.report("error, no format found with name: %s",formatname) end end end +local fallback = { + en = "cont-en", + uk = "cont-uk", + de = "cont-de", + fr = "cont-fr", + nl = "cont-nl", + cz = "cont-cz", + it = "cont-it", + ro = "cont-ro", +} + +local defaults = { + "cont-en", + "cont-nl", + "mptopdf", + "plain" +} + function scripts.context.make() - local list = (environment.files[1] and environment.files) or { "cont-en", "cont-nl", "mptopdf" } + local list = (environment.files[1] and environment.files) or defaults for _, name in ipairs(list) do + name = fallback[name] or name local command = "luatools --make --compile " .. name - input.report("running command: " .. command) + input.report("running command: %s",command) os.spawn(command) end end @@ -601,7 +671,7 @@ end function scripts.context.generate() -- hack, should also be a shared function local command = "luatools --generate " - input.report("running command: " .. command) + input.report("running command: %s",command) os.spawn(command) end @@ -613,14 +683,14 @@ function scripts.context.ctx() end function scripts.context.version() - local name = input.find_file(instance,"context.tex") + local name = input.find_file("context.tex") if name ~= "" then - input.report(string.format("main context file: %s",name)) + input.report("main context file: %s",name) local data = io.loaddata(name) if data then local version = data:match("\\edef\\contextversion{(.-)}") if version then - input.report(string.format("current version : %s",version)) + input.report("current version: %s",version) else input.report("context version: unknown, no timestamp found") end @@ -632,10 +702,87 @@ function scripts.context.version() end end +local generic_files = { + "texexec.tex", "texexec.tui", "texexec.tuo", + "texexec.tuc", "texexec.tua", + "texexec.ps", "texexec.pdf", "texexec.dvi", + "cont-opt.tex", "cont-opt.bak" +} + +local obsolete_results = { + "dvi", +} + +local temporary_runfiles = { + "tui", "tua", "tup", "ted", "tes", "top", + "log", "tmp", "run", "bck", "rlg", + "mpt", "mpx", "mpd", "mpo", "mpb", + "ctl", +} + +local persistent_runfiles = { + "tuo", "tub", "top", "tuc" +} + +local function purge_file(dfile,cfile) + if cfile and lfs.isfile(cfile) then + if os.remove(dfile) then + return file.basename(dfile) + end + else + if os.remove(dfile) then + return file.basename(dfile) + end + end +end + +function scripts.context.purge_job(jobname,all) + local filebase = file.removesuffix(jobname) + local deleted = { } + for _, suffix in ipairs(obsolete_results) do + deleted[#deleted+1] = purge_file(filebase.."."..suffix,filebase..".pdf") + end + for _, suffix in ipairs(temporary_runfiles) do + deleted[#deleted+1] = purge_file(filebase.."."..suffix) + end + if all then + for _, suffix in ipairs(persistent_runfiles) do + deleted[#deleted+1] = purge_file(filebase.."."..suffix) + end + end + if #deleted > 0 then + input.report("purged files: %s", table.join(deleted,", ")) + end +end + +function scripts.context.purge(all) + local all = all or environment.argument("all") + local pattern = environment.argument("pattern") or "*.*" + local files = dir.glob(pattern) + local obsolete = table.tohash(obsolete_results) + local temporary = table.tohash(temporary_runfiles) + local persistent = table.tohash(persistent_runfiles) + local generic = table.tohash(generic_files) + local deleted = { } + for _, name in ipairs(files) do + local suffix = file.extname(name) + local basename = file.basename(name) + if obsolete[suffix] or temporary[suffix] or persistent[suffix] or generic[basename] then + deleted[#deleted+1] = purge_file(name) + end + end + if #deleted > 0 then + input.report("purged files: %s", table.join(deleted,", ")) + end +end + +--~ purge_for_files("test",true) +--~ purge_all_files() + function scripts.context.touch() if environment.argument("expert") then local function touch(name,pattern) - local name = input.find_file(instance,name) + local name = input.find_file(name) local olddata = io.loaddata(name) if olddata then local oldversion, newversion = "", os.date("%Y.%M.%d %H:%m") @@ -656,12 +803,12 @@ function scripts.context.touch() end local done, oldversion, newversion, foundname = touch("context.tex", "(\\edef\\contextversion{)(.-)(})") if done then - input.report(string.format("old version : %s", oldversion)) - input.report(string.format("new version : %s", newversion)) - input.report(string.format("touched file: %s", foundname)) + input.report("old version : %s", oldversion) + input.report("new version : %s", newversion) + input.report("touched file: %s", foundname) local ok, _, _, foundname = touch("cont-new.tex", "(\\newcontextversion{)(.-)(})") if ok then - input.report(string.format("touched file: %s", foundname)) + input.report("touched file: %s", foundname) end end end @@ -671,18 +818,22 @@ function scripts.context.timed(action) input.starttiming(scripts.context) action() input.stoptiming(scripts.context) - input.report("total runtime: " .. input.elapsedtime(scripts.context)) + input.report("total runtime: %s",input.elapsedtime(scripts.context)) end banner = banner .. " | context tools " messages.help = [[ --run process (one or more) files (default action) ---make create context formats formats +--make create context formats --generate generate file database etc. --ctx=name use ctx file --version report installed context version ---autopdf open pdf file afterwards +--forcexml force xml stub (optional flag: --mkii) +--autopdf close pdf file in viewer and start pdf viewer afterwards +--once only one run +--purge(all) purge files (--pattern=...) +--result=name rename result to given name --expert expert options ]] @@ -703,18 +854,26 @@ if environment.argument("run") then scripts.context.timed(scripts.context.run) elseif environment.argument("make") then scripts.context.timed(scripts.context.make) +elseif environment.argument("generate") then + scripts.context.timed(scripts.context.generate) elseif environment.argument("ctx") then scripts.context.timed(scripts.context.ctx) elseif environment.argument("version") then scripts.context.version() elseif environment.argument("touch") then scripts.context.touch() -elseif environment.argument("help") then - input.help(banner,messages.help) elseif environment.argument("expert") then input.help(banner,messages.expert) +elseif environment.argument("help") then + input.help(banner,messages.help) elseif environment.files[1] then scripts.context.timed(scripts.context.run) +elseif environment.argument("purge") then + -- only when no filename given, supports --pattern + scripts.context.purge() +elseif environment.argument("purgeall") then + -- only when no filename given, supports --pattern + scripts.context.purge(true) else input.help(banner,messages.help) end diff --git a/scripts/context/lua/mtx-convert.lua b/scripts/context/lua/mtx-convert.lua index 1bfc10c0f..eca050f29 100644 --- a/scripts/context/lua/mtx-convert.lua +++ b/scripts/context/lua/mtx-convert.lua @@ -14,30 +14,53 @@ do local gsprogram = (os.platform == "windows" and "gswin32c") or "gs" local gstemplate = "%s -q -sDEVICE=pdfwrite -dEPSCrop -dNOPAUSE -dNOCACHE -dBATCH -dAutoRotatePages=/None -dProcessColorModel=/DeviceCMYK -sOutputFile=%s %s -c quit" - function graphics.converters.epstopdf(inputpath,outputpath,epsname) - inputpath = inputpath or "." - outputpath = outputpath or "." - local oldname = file.join(inputpath,epsname) - local newname = file.join(outputpath,file.replacesuffix(epsname,"pdf")) - local et = lfs.attributes(oldname,"modification") - local pt = lfs.attributes(newname,"modification") - if not pt or et > pt then - dir.mkdirs(outputpath) - local tmpname = file.replacesuffix(newname,"tmp") - local command = string.format(gstemplate,gsprogram,tmpname,oldname) - os.spawn(command) - os.remove(newname) - os.rename(tmpname,newname) - end + function graphics.converters.eps(oldname,newname) + return gstemplate:format(gsprogram,newname,oldname) + end + + local improgram = "convert" + local imtemplate = { + low = "%s -quality 0 -compress zip %s pdf:%s", + medium = "%s -quality 75 -compress zip %s pdf:%s", + high = "%s -quality 100 -compress zip %s pdf:%s", + } + + function graphics.converters.jpg(oldname,newname) + local ea = environment.arguments + local quality = (ea.high and 'high') or (ea.medium and 'medium') or (ea.low and 'low') or 'high' + return imtemplate[quality]:format(improgram,oldname,newname) end + graphics.converters.tif = graphics.converters.jpg + graphics.converters.tiff = graphics.converters.jpg + graphics.converters.png = graphics.converters.jpg + function graphics.converters.convertpath(inputpath,outputpath) - for name in lfs.dir(inputpath or ".") do + inputpath = inputpath or "." + outputpath = outputpath or "." + for name in lfs.dir(inputpath) do + local suffix = file.extname(name) if name:find("%.$") then -- skip . and .. - elseif name:find("%.eps$") then - graphics.converters.epstopdf(inputpath,outputpath, name) - elseif lfs.attributes(inputpath .. "/".. name,"mode") == "directory" then + elseif graphics.converters[suffix] then + local oldname = file.join(inputpath,name) + local newname = file.join(outputpath,file.replacesuffix(name,"pdf")) + local et = lfs.attributes(oldname,"modification") + local pt = lfs.attributes(newname,"modification") + if not pt or et > pt then + dir.mkdirs(outputpath) + local tmpname = file.replacesuffix(newname,"tmp") + local command = graphics.converters[suffix](oldname,tmpname) + input.report("command: %s",command) + io.flush() + os.spawn(command) + os.remove(newname) + os.rename(tmpname,newname) + if lfs.attributes(newname,"size") == 0 then + os.remove(newname) + end + end + elseif lfs.isdir(inputpath .. "/".. name) then graphics.converters.convertpath(inputpath .. "/".. name,outputpath .. "/".. name) end end @@ -45,8 +68,6 @@ do end -texmf.instance = instance -- we need to get rid of this / maybe current instance in global table - scripts = scripts or { } scripts.convert = scripts.convert or { } diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua index 395e9764e..c9f1d2f18 100644 --- a/scripts/context/lua/mtx-fonts.lua +++ b/scripts/context/lua/mtx-fonts.lua @@ -6,15 +6,13 @@ if not modules then modules = { } end modules ['mtx-fonts'] = { license = "see context related readme files" } -dofile(input.find_file(instance,"font-syn.lua")) - -texmf.instance = instance -- we need to get rid of this / maybe current instance in global table +dofile(input.find_file("font-syn.lua")) scripts = scripts or { } scripts.fonts = scripts.fonts or { } -function scripts.fonts.reload() - fonts.names.load(true) +function scripts.fonts.reload(verbose) + fonts.names.load(true,verbose) end function scripts.fonts.list(pattern,reload,all) @@ -42,7 +40,8 @@ function scripts.fonts.list(pattern,reload,all) end) action(function(v,n,f,s) if s then s = "(sub)" else s = "" end - print(string.format("%s %s %s %s",v:padd(w[1]," "),n:padd(w[2]," "),f:padd(w[3]," "), s)) + local str = string.format("%s %s %s %s",v:padd(w[1]," "),n:padd(w[2]," "),f:padd(w[3]," "), s) + print(str:strip()) end) end end @@ -51,13 +50,13 @@ function scripts.fonts.save(name,sub) local function save(savename,fontblob) if fontblob then savename = savename:lower() .. ".lua" - logs.report("fontsave","saving data in " .. savename) + logs.report("fontsave","saving data in %s",savename) table.tofile(savename,fontforge.to_table(fontblob),"return") fontforge.close(fontblob) end end if name and name ~= "" then - local filename = input.find_file(texmf.instance,name) -- maybe also search for opentype + local filename = input.find_file(name) -- maybe also search for opentype if filename and filename ~= "" then local suffix = file.extname(filename) if suffix == 'ttf' or suffix == 'otf' or suffix == 'ttc' then @@ -88,7 +87,8 @@ messages.help = [[ ]] if environment.argument("reload") then - scripts.fonts.reload() + local verbose = environment.argument("verbose") + scripts.fonts.reload(verbose) elseif environment.argument("list") then local pattern = environment.argument("pattern") or environment.files[1] or "" local all = environment.argument("all") diff --git a/scripts/context/lua/mtx-grep.lua b/scripts/context/lua/mtx-grep.lua new file mode 100644 index 000000000..18e36d2ea --- /dev/null +++ b/scripts/context/lua/mtx-grep.lua @@ -0,0 +1,80 @@ +if not modules then modules = { } end modules ['mtx-babel'] = { + 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" +} + +scripts = scripts or { } +scripts.grep = scripts.grep or { } + +banner = banner .. " | simple grepper " + +function scripts.grep.find(pattern, files, offset) + if pattern and pattern ~= "" then + local format = string.format + input.starttiming(scripts.grep) + local count, nofmatches, noffiles, nofmatchedfiles = environment.argument("count"), 0, 0, 0 + local function grep(name) + local data = io.loaddata(name) + if data then + noffiles = noffiles + 1 + local n, m = 0, 0 + for line in data:gmatch("[^\n]+") do -- faster than loop over lines + n = n + 1 + if line:find(pattern) then + m = m + 1 + if not count then + input.log(format("%s %s: %s",name,n,line)) + io.flush() + end + end + end + if count and m > 0 then + nofmatches = nofmatches + m + nofmatchedfiles = nofmatchedfiles + 1 + input.log(format("%s: %s",name,m)) + io.flush() + end + end + end +--~ for i=offset or 1, #files do +--~ local filename = files[i] +--~ if filename:find("%*") then +--~ for _, name in ipairs(dir.glob(filename)) do +--~ grep(name) +--~ end +--~ else +--~ grep(filename) +--~ end +--~ end + for i=offset or 1, #files do + for _, name in ipairs(dir.glob(files[i])) do + grep(name) + end + end + input.stoptiming(scripts.grep) + if count and nofmatches > 0 then + input.log(format("\nfiles: %s, matches: %s, matched files: %s, runtime: %0.3f seconds",noffiles,nofmatches,nofmatchedfiles,input.loadtime(scripts.grep))) + end + end +end + +messages.help = [[ +--pattern search for pattern (optional) +--count count matches only +]] + +input.verbose = true + +local pattern = environment.argument("pattern") +local files = environment.files and #environment.files > 0 and environment.files + +if pattern and files then + scripts.grep.find(pattern, files) +elseif files then + scripts.grep.find(files[1], files, 2) +else + input.help(banner,messages.help) +end diff --git a/scripts/context/lua/mtx-mptopdf.lua b/scripts/context/lua/mtx-mptopdf.lua new file mode 100644 index 000000000..0c685a249 --- /dev/null +++ b/scripts/context/lua/mtx-mptopdf.lua @@ -0,0 +1,138 @@ +if not modules then modules = { } end modules ['mtx-mptopdf'] = { + version = 1.303, + comment = "companion to mtxrun.lua", + author = "Taco Hoekwater, Elvenkind BV, Dordrecht NL", + copyright = "Elvenkind BV / ConTeXt Development Team", + license = "see context related readme files" +} + +scripts = scripts or { } +scripts.mptopdf = scripts.mptopdf or { } +scripts.mptopdf.aux = scripts.mptopdf.aux or { } + +do + -- setup functions and variables here + + local dosish, miktex, escapeshell = false, false, false + + if os.platform == 'windows' then + dosish = true + if environment.TEXSYSTEM and environment.TEXSYSTEM:find("miktex") then + miktex = true + end + end + if environment.SHELL and environment.SHELL:find("sh") then + escapeshell = true + end + + function scripts.mptopdf.aux.find_latex(fname) + local d = io.loaddata(fname) or "" + return d:find("\\documentstyle") or d:find("\\documentclass") or d:find("\\begin{document}") + end + + function scripts.mptopdf.aux.do_convert (fname) + local command, done, pdfdest = "", 0, "" + if fname:find(".%d+$") or fname:find("%.mps$") then + if miktex then + command = "pdftex -undump=mptopdf" + else + command = "pdftex -fmt=mptopdf -progname=context" + end + if dosish then + command = string.format('%s \\relax "%s"',command,fname) + else + command = string.format('%s \\\\relax "%s"',command,fname) + end + os.execute(command) + local name, suffix = file.nameonly(fname), file.extname(fname) + local pdfsrc = name .. ".pdf" + if lfs.isfile(pdfsrc) then + pdfdest = name .. "-" .. suffix .. ".pdf" + os.rename(pdfsrc, pdfdest) + if lfs.isfile(pdfsrc) then -- rename failed + file.copy(pdfsrc, pdfdest) + end + done = 1 + end + end + return done, pdfdest + end + + function scripts.mptopdf.aux.make_mps(fn,latex,rawmp,metafun) + local rest, mpbin = latex and " --tex=latex " or " ", "" + if rawmp then + if metafun then + mpbin = "mpost --progname=mpost --mem=metafun" + else + mpbin = "mpost --mem=mpost" + end + else + if latex then + mpbin = "mpost --mem=mpost" + else + mpbin = "texexec --mptex" + end + end + local runner = mpbin .. rest .. fn + input.report("running: %s\n", runner) + return (os.execute(runner)) + end + +end + +function scripts.mptopdf.convertall() + local rawmp = environment.arguments.rawmp or false + local metafun = environment.arguments.metafun or false + local latex = environment.arguments.latex or false + local files = dir.glob(environment.files) + if #files > 0 then + local fn = files[1] + if #files == 1 and fn:find("%.mp$") then + latex = scripts.mptopdf.aux.find_latex(fn) or latex + end + if scripts.mptopdf.aux.make_mps(fn,latex,rawmp,metafun) then + files = dir.glob(file.nameonly(fn) .. ".*") -- reset + else + input.report("error while processing mp file '%s'", fn) + exit(1) + end + local report = { } + for _,fn in ipairs(files) do + local success, name = scripts.mptopdf.aux.do_convert(fn) + if success > 0 then + report[#report+1] = { fn, name } + end + end + if #report > 0 then + input.report("number of converted files: %i", #report) + input.report("") + for _, r in ipairs(report) do + input.report("%s => %s", r[1], r[2]) + end + else + input.report("no input files match %s", table.concat(files,' ')) + end + else + input.report("no files match %s", table.concat(environment.files,' ')) + end +end + +banner = banner .. " | mptopdf converter " + +messages.help = [[ +--rawmp raw metapost run +--metafun use metafun instead of plain +--latex force --tex=latex +]] + +input.verbose = true + +if environment.files[1] then + scripts.mptopdf.convertall() +else + if not environment.arguments.help then + input.report("provide MP output file (or pattern)") + input.report("") + end + input.help(banner,messages.help) +end diff --git a/scripts/context/lua/mtx-patterns.lua b/scripts/context/lua/mtx-patterns.lua new file mode 100644 index 000000000..be190af43 --- /dev/null +++ b/scripts/context/lua/mtx-patterns.lua @@ -0,0 +1,362 @@ +if not modules then modules = { } end modules ['mtx-patterns'] = { + 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" +} + +local format = string.format + +scripts = scripts or { } +scripts.patterns = scripts.patterns or { } + +scripts.patterns.list = { + { "??", "hyph-ar.tex", "arabic" }, + { "bg", "hyph-bg.tex", "bulgarian" }, +-- { "ca", "hyph-ca.tex", "" }, + { "??", "hyph-cop.tex", "coptic" }, + { "cs", "hyph-cs.tex", "czech" }, + { "??", "hyph-cy.tex", "welsh" }, + { "da", "hyph-da.tex", "danish" }, + { "de", "hyph-de-1901.tex", "german, old spelling" }, + { "deo", "hyph-de-1996.tex", "german, new spelling" }, +--~ { "??", "hyph-el-monoton.tex", "" }, +--~ { "??", "hyph-el-polyton.tex", "" }, +--~ { "agr", "hyph-grc", "ancient greek" }, +--~ { "???", "hyph-x-ibycus", "ancient greek in ibycus encoding" }, +--~ { "gr", "", "" }, + { "??", "hyph-eo.tex", "esperanto" }, + { "gb", "hyph-en-gb.tex", "british english" }, + { "us", "hyph-en-us.tex", "american english" }, + { "es", "hyph-es.tex", "spanish" }, + { "et", "hyph-et.tex", "estonian" }, + { "eu", "hyph-eu.tex", "basque" }, -- ba is Bashkir! + { "??", "hyph-fa.tex", "farsi" }, + { "fi", "hyph-fi.tex", "finnish" }, + { "fr", "hyph-fr.tex", "french" }, +-- { "??", "hyph-ga.tex", "" }, +-- { "??", "hyph-gl.tex", "" }, +-- { "??", "hyph-grc.tex", "" }, + { "hr", "hyph-hr.tex", "croatian" }, + { "??", "hyph-hsb.tex", "upper sorbian" }, + { "hu", "hyph-hu.tex", "hungarian" }, + { "??", "hyph-ia.tex", "interlingua" }, + { "??", "hyph-id.tex", "indonesian" }, + { "??", "hyph-is.tex", "icelandic" }, + { "it", "hyph-it.tex", "italian" }, + { "la", "hyph-la.tex", "latin" }, + { "??", "hyph-mn-cyrl.tex", "mongolian, cyrillic script" }, + { "??", "hyph-mn-cyrl-x-new.tex", "mongolian, cyrillic script (new patterns)" }, + { "nb", "hyph-nb.tex", "norwegian bokmål" }, + { "nl", "hyph-nl.tex", "dutch" }, + { "nn", "hyph-nn.tex", "norwegian nynorsk" }, + { "pl", "hyph-pl.tex", "polish" }, + { "pt", "hyph-pt.tex", "portuguese" }, + { "ro", "hyph-ro.tex", "romanian" }, + { "ru", "hyph-ru.tex", "russian" }, + { "sk", "hyph-sk.tex", "" }, + { "sl", "hyph-sl.tex", "slovenian" }, + { "??", "hyph-sr-cyrl.tex", "serbian" }, + { "sv", "hyph-sv.tex", "swedish" }, + { "tr", "hyph-tr.tex", "turkish" }, + { "??", "hyph-uk.tex", "ukrainian" }, + { "??", "hyph-zh-latn.tex", "zh-latn, chinese Pinyin" }, +} + + +-- stripped down from lpeg example: + +local utf = unicode.utf8 + +local cont = lpeg.R("\128\191") -- continuation byte + +local utf8 = lpeg.R("\0\127") + + lpeg.R("\194\223") * cont + + lpeg.R("\224\239") * cont * cont + + lpeg.R("\240\244") * cont * cont * cont + +local validutf = (utf8^0/function() return true end) * (lpeg.P(-1)/function() return false end) + +function utf.check(str) + return lpeg.match(validutf,str) +end + +local permitted_commands = table.tohash { + "message", + "endinput" +} + +local permitted_characters = table.tohash { + 0x0027, -- apostrofe + 0x002D, -- hyphen +} + +function scripts.patterns.load(path,name,mnemonic,fullcheck) + local fullname = file.join(path,name) + local data = io.loaddata(fullname) or "" + local byte, char = utf.byte, utf.char + if data ~= "" then + data = data:gsub("\\input ([^ \n\r]+)", function(subname) + local subname = file.addsuffix(subname,"tex") + local subfull = file.join(file.dirname(name),subname) + local subdata = io.loaddata(subfull) or "" + if subefile == "" then + if mnemonic then + input.report("no subfile %s for language %s",subname,mnemonic) + else + input.report("no subfile %s",name) + end + end + return subdata + end) + local comment = data:match("^(.-)[\n\r]\\patterns") or "" + local n, okay = 0, true + local cd = characters.data + for line in data:gmatch("[^ \n\r]+") do + local ok = utf.check(line) + n = n + 1 + if not ok then + okay = false + line = line:gsub("%%","%%%%") + if fullcheck then + if mnemonic then + input.report("invalid utf in language %s, file %s, line %s: %s",mnemonic,name,n,line) + else + input.report("invalid utf in file %s, line %s: %s",name,n,line) + end + else + if mnemonic then + input.report("file %s for %s contains invalid utf",name,mnemonic) + else + input.report("file %s contains invalid utf",name) + end + break + end + end + end + local c, h = { }, { } + for line in data:gmatch("[^\n\r]+") do + local txt, cmt = line:match("^(.-)%%(.*)$") + if not txt then + txt, cmt = line, "" + end + for s in txt:gmatch("\\([a-zA-Z]+)") do + h[s] = (h[s] or 0) + 1 + end + for s in cmt:gmatch("\\([a-zA-Z]+)") do + c[s] = (c[s] or 0) + 1 + end + end + h.patterns = nil + h.hyphenation = nil + for k, v in pairs(h) do + if not permitted_commands[k] then okay = false end + if mnemonic then + input.report("command \\%s found in language %s, file %s, n=%s",k,mnemonic,name,v) + else + input.report("command \\%s found in file %s, n=%s",k,name,v) + end + end + if not environment.argument("fast") then + for k, v in pairs(c) do + if mnemonic then + input.report("command \\%s found in comment of language %s, file %s, n=%s",k,mnemonic,name,v) + else + input.report("command \\%s found in comment of file %s, n=%s",k,name,v) + end + end + end + data = data:gsub("%%.-[\n\r]","") + data = data:gsub(" *[\n\r]+","\n") + local patterns = data:match("\\patterns[%s]*{[%s]*(.-)[%s]*}") or "" + local hyphenations = data:match("\\hyphenation[%s]*{[%s]*(.-)[%s]*}") or "" + patterns = patterns:gsub(" +","\n") + hyphenations = hyphenations:gsub(" +","\n") + local p, h = { }, { } + local pats, hyps = { } , { } + local pused, hused = { } , { } + local period = byte(".") + for line in patterns:gmatch("[^ \n\r]+") do + local ok = true + for b in line:utfvalues() do + if b == period then + -- ok + else + local ct = cd[b].category + if ct == "lu" or ct == "ll" then + pused[char(b)] = true + elseif ct == "nd" then + -- ok + else + p[b] = (p[b] or 0) + 1 + ok = false + end + end + end + if ok then + pats[#pats+1] = line + end + end + local hyphen = byte("-") + for line in hyphenations:gmatch("[^ \n\r]+") do + local ok = true + for b in line:utfvalues() do + if b == hyphen then + -- ok + else + local ct = cd[b].category + if ct == "lu" or ct == "ll" then + hused[char(b)] = true + else + h[b] = (h[b] or 0) + 1 + ok = false + end + end + end + if ok then + hyps[#hyps+1] = line + end + end + local stripped = { } + for k, v in pairs(p) do + if mnemonic then + input.report("invalid character %s (0x%04X) in patterns of language %s, file %s, n=%s",char(k),k,mnemonic,name,v) + else + input.report("invalid character %s (0x%04X) in patterns of file %s, n=%s",char(k),k,name,v) + end + if not permitted_characters[k] then + okay = false + else + stripped[k] = true + end + end + for k, v in pairs(h) do + if mnemonic then + input.report("invalid character %s (0x%04X) in exceptions of language %s, file %s, n=%s",char(k),k,mnemonic,name,v) + else + input.report("invalid character %s (0x%04X) in exceptions of file %s, n=%s",char(k),k,name,v) + end + if not permitted_characters[k] then + okay = false + else + stripped[k] = true + end + end + local stripset = "" + for k, v in pairs(stripped) do + input.report("entries that contain character %s will be omitted",char(k)) + stripset = stripset .. "%" .. char(k) + end + return okay, pats, hyps, comment, stripset, pused, hused + else + if mnemonic then + input.report("no file %s for language %s",fullname,mnemonic) + else + input.report("no file %s",fullname) + end + return false, { }, { }, "", "", { }, { } + end +end + +function scripts.patterns.save(destination,mnemonic,patterns,hyphenations,comment,stripped,pused,hused) + local nofpatterns = #patterns + local nofhyphenations = #hyphenations + local pu = table.concat(table.sortedkeys(pused), " ") + local hu = table.concat(table.sortedkeys(hused), " ") + input.report("language %s has %s patterns and %s exceptions",mnemonic,nofpatterns,nofhyphenations) + if mnemonic ~= "??" then + local rmefile = file.join(destination,"lang-"..mnemonic..".rme") + local patfile = file.join(destination,"lang-"..mnemonic..".pat") + local hypfile = file.join(destination,"lang-"..mnemonic..".hyp") + local topline = "% generated by mtxrun --script pattern --convert" + local banner = "% for comment and copyright, see " .. rmefile + input.report("saving language data for %s",mnemonic) + if not comment or comment == "" then comment = "% no comment" end + if not type(destination) == "string" then destination = "." end + os.remove(rmefile) + os.remove(patfile) + os.remove(hypfile) + io.savedata(rmefile,format("%s\n\n%s",topline,comment)) + io.savedata(patfile,format("%s\n\n%s\n\n%% used: %s\n\n\\patterns{\n%s}",topline,banner,pu,table.concat(patterns,"\n"))) + io.savedata(hypfile,format("%s\n\n%s\n\n%% used: %s\n\n\\hyphenation{\n%s}",topline,banner,hu,table.concat(hyphenations,"\n"))) + end +end + +function scripts.patterns.prepare() + dofile(input.find_file("char-def.lua")) +end + +function scripts.patterns.check() + local path = environment.argument("path") or "." + local found = false + local verbose = input.verbose + input.verbose = true + if #environment.files > 0 then + for _, name in ipairs(environment.files) do + input.report("checking language file %s", name) + local okay = scripts.patterns.load(path,name,nil,not environment.argument("fast")) + if #environment.files > 1 then + input.report("") + end + end + else + for k, v in pairs(scripts.patterns.list) do + local mnemonic, name = v[1], v[2] + input.report("checking language %s, file %s", mnemonic, name) + local okay = scripts.patterns.load(path,name,mnemonic,not environment.argument("fast")) + if not okay then + input.report("there are errors that need to be fixed") + end + input.report("") + end + end + input.verbose = verbose +end + +function scripts.patterns.convert() + local path = environment.argument("path") or "." + local destination = environment.argument("destination") or "." + if path == destination then + input.report("source path and destination path should differ (use --path and/or --destination)") + else + local verbose = input.verbose + input.verbose = true + for k, v in pairs(scripts.patterns.list) do + local mnemonic, name = v[1], v[2] + input.report("converting language %s, file %s", mnemonic, name) + local okay, patterns, hyphenations, comment, stripped, pused, hused = scripts.patterns.load(path,name,false) + if okay then + scripts.patterns.save(destination,mnemonic,patterns,hyphenations,comment,stripped,pused,hused) + else + input.report("convertion aborted due to error(s)") + end + input.report("") + end + end + input.verbose = verbose +end + +banner = banner .. " | pattern tools " + +messages.help = [[ +--convert generate context language files (mnemonic driven, if not given then all) +--check check pattern file (or those used by context when no file given) + +--fast only report filenames, no lines +]] + +if environment.argument("check") then + scripts.patterns.prepare() + scripts.patterns.check() +elseif environment.argument("convert") then + scripts.patterns.prepare() + scripts.patterns.convert() +else + input.help(banner,messages.help) +end + +-- mtxrun --script pattern --check hyph-*.tex +-- mtxrun --script pattern --check --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns +-- mtxrun --script pattern --check --fast --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns +-- mtxrun --script pattern --convert --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns --destination e:/tmp/patterns diff --git a/scripts/context/lua/mtx-server.lua b/scripts/context/lua/mtx-server.lua index 293bc0c1c..1df4b4663 100644 --- a/scripts/context/lua/mtx-server.lua +++ b/scripts/context/lua/mtx-server.lua @@ -1,82 +1,283 @@ if not modules then modules = { } end modules ['mtx-server'] = { version = 1.001, comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + author = "Hans Hagen & Taco Hoekwater", 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 {} +scripts.webserver = scripts.webserver or { } local socket = require("socket") +local format = string.format + +-- The following two lists are taken from webrick (ruby) and +-- extended with a few extra suffixes. + +local mimetypes = { + ai = 'application/postscript', + asc = 'text/plain', + avi = 'video/x-msvideo', + bin = 'application/octet-stream', + bmp = 'image/bmp', + bz2 = 'application/x-bzip2', + cer = 'application/pkix-cert', + class = 'application/octet-stream', + crl = 'application/pkix-crl', + crt = 'application/x-x509-ca-cert', + css = 'text/css', + dms = 'application/octet-stream', + doc = 'application/msword', + dvi = 'application/x-dvi', + eps = 'application/postscript', + etx = 'text/x-setext', + exe = 'application/octet-stream', + gif = 'image/gif', + gz = 'application/x-tar', + hqx = 'application/mac-binhex40', + htm = 'text/html', + html = 'text/html', + jpe = 'image/jpeg', + jpeg = 'image/jpeg', + jpg = 'image/jpeg', + lha = 'application/octet-stream', + lzh = 'application/octet-stream', + mov = 'video/quicktime', + mpe = 'video/mpeg', + mpeg = 'video/mpeg', + mpg = 'video/mpeg', + pbm = 'image/x-portable-bitmap', + pdf = 'application/pdf', + pgm = 'image/x-portable-graymap', + png = 'image/png', + pnm = 'image/x-portable-anymap', + ppm = 'image/x-portable-pixmap', + ppt = 'application/vnd.ms-powerpoint', + ps = 'application/postscript', + qt = 'video/quicktime', + ras = 'image/x-cmu-raster', + rb = 'text/plain', + rd = 'text/plain', + rgb = 'image/x-rgb', + rtf = 'application/rtf', + sgm = 'text/sgml', + sgml = 'text/sgml', + snd = 'audio/basic', + tar = 'application/x-tar', + tgz = 'application/x-tar', + tif = 'image/tiff', + tiff = 'image/tiff', + txt = 'text/plain', + xbm = 'image/x-xbitmap', + xls = 'application/vnd.ms-excel', + xml = 'text/xml', + xpm = 'image/x-xpixmap', + xwd = 'image/x-xwindowdump', + zip = 'application/zip', +} + +local messages = { + [100] = 'Continue', + [101] = 'Switching Protocols', + [200] = 'OK', + [201] = 'Created', + [202] = 'Accepted', + [203] = 'Non-Authoritative Information', + [204] = 'No Content', + [205] = 'Reset Content', + [206] = 'Partial Content', + [300] = 'Multiple Choices', + [301] = 'Moved Permanently', + [302] = 'Found', + [303] = 'See Other', + [304] = 'Not Modified', + [305] = 'Use Proxy', + [307] = 'Temporary Redirect', + [400] = 'Bad Request', + [401] = 'Unauthorized', + [402] = 'Payment Required', + [403] = 'Forbidden', + [404] = 'Not Found', + [405] = 'Method Not Allowed', + [406] = 'Not Acceptable', + [407] = 'Proxy Authentication Required', + [408] = 'Request Timeout', + [409] = 'Conflict', + [410] = 'Gone', + [411] = 'Length Required', + [412] = 'Precondition Failed', + [413] = 'Request Entity Too Large', + [414] = 'Request-URI Too Large', + [415] = 'Unsupported Media Type', + [416] = 'Request Range Not Satisfiable', + [417] = 'Expectation Failed', + [500] = 'Internal Server Error', + [501] = 'Not Implemented', + [502] = 'Bad Gateway', + [503] = 'Service Unavailable', + [504] = 'Gateway Timeout', + [505] = 'HTTP Version Not Supported', +} + +local handlers = { } + +local function errormessage(client,configuration,n) + local data = format("<head><title>%s %s</title></head><html><h2>%s %s</h2></html>",n,messages[n],n,messages[n]) + input.report("handling error %s: %s",n,messages[n]) + handlers.generic(client,configuration,data,nil,true) +end -local function message(str) - return string.format("<h1>%s</h1>",str) +function handlers.generic(client,configuration,data,suffix,iscontent) + if not iscontent then + data = io.loaddata(file.join(configuration.root,data)) + end + if data and data ~= "" then + client:send("HTTP/1.1 200 OK\r\n") + client:send("Connection: close\r\n") + client:send(format("Content-Length: %s\r\n",#data)) + client:send(format("Content-Type: %s\r\n",(suffix and mimetypes[suffix]) or "text/html")) + client:send("\r\n") + client:send(data) + client:send("\r\n") + else + errormessage(client,configuration,404) + end +end + +--~ return os.date() + +--~ return { content = "crap" } + +--~ return function(configuration,filename) +--~ return { content = filename } +--~ end + +function handlers.lua(client,configuration,filename,suffix,iscontent) + local filename = file.join(configuration.root,configuration.scripts,filename) + -- todo: split url in components, see l-url; rather trivial + if lfs.isfile(filename) then + local result = loadfile(filename) + if result and type(result) == "function" then + -- result() should return a table { [type=,] [length=,] content= }, function or string + result = result() + end + if result and type(result) == "function" then + result = result(configuration,filename) -- sedond argument will become query + end + if result and type(result) == "string" then + result = { content = result } + end + if result and type(result) == "table" then + if result.content then + local suffix = result.type or "text/html" + local action = handlers[suffix] or handlers.generic + action(client,configuration,filename,suffix,true) -- content + elseif result.filename then + local suffix = file.extname(filename) or "text/html" + local action = handlers[suffix] or handlers.generic + action(client,configuration,filename,suffix,false) -- filename + else + errormessage(client,configuration,404) + end + else + errormessage(client,configuration,500) + end + else + errormessage(client,configuration,404) + end end +handlers.luc = handlers.lua +handlers.html = handlers.htm + +local indices = { "index.htm", "index.html" } + function scripts.webserver.run(configuration) - local server = assert(socket.bind("*", tonumber(configuration.port or 8080))) - while true do + -- check configuration + configuration.port = tonumber(configuration.port or os.getenv("MTX_SERVER_PORT") or 8080) or 8080 + if not configuration.root or not lfs.isdir(configuration.root) then + configuration.root = os.getenv("MTX_SERVER_ROOT") or "." + end + -- locate root and index file in tex tree + if not lfs.isdir(configuration.root) then + for _, name in ipairs(indices) do + local root = input.resolve("path:" .. name) or "" + if root ~= "" then + configuration.root = root + configuration.index = configuration.index or name + break + end + end + end + if not configuration.index then + for _, name in ipairs(indices) do + if lfs.isfile(file.join(configuration.root,name)) then + configuration.index = name -- we will prepend the rootpath later + break + end + end + configuration.index = configuration.index or "unknown" + end + configuration.scripts = configuration.scripts or "cgi" + -- so far for checks + input.report("running at port: %s",configuration.port) + input.report("document root: %s",configuration.root) + input.report("main index file: %s",configuration.index) + input.report("scripts subpath: %s",configuration.scripts) + local server = assert(socket.bind("*", configuration.port)) + while true do -- no multiple clients local client = server:accept() client:settimeout(configuration.timeout or 60) local request, e = client:receive() if e then - client:send(message("404 Not Found")) + errormessage(client,configuration,404) else - -- GET /showcase.pdf HTTP/1.1 + local from = client:getpeername() + input.report("request from: %s",tostring(from)) 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") + if filename then + filename = socket.url.unescape(filename) + input.report("requested action: %s",filename) + if filename:find("%.%.") then + filename = nil -- invalid path + end + if filename == nil or filename == "" or filename == "/" then + filename = configuration.index + input.report("invalid filename, forcing: %s",filename) + end + local suffix = file.extname(filename) + local action = handlers[suffix] or handlers.generic + if action then + input.report("performing action: %s",filename) + action(client,configuration,filename,suffix,false) -- filename and no content else - client:send("Content-Type: text/html\r\n") + errormessage(client,configuration,404) end - client:send("\r\n") - client:send(data) - client:send("\r\n") else - client:send(message("404 Not Found")) + errormessage(client,configuration,404) end end client:close() end end - banner = banner .. " | webserver " messages.help = [[ --start start server --port port to listen to --root server root +--scripts scripts sub path --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", + port = environment.argument("port"), + root = environment.argument("root"), -- "e:/websites/www.pragma-ade.com", + index = environment.argument("index"), + scripts = environment.argument("scripts") or "cgi", } else input.help(banner,messages.help) diff --git a/scripts/context/lua/mtx-update.lua b/scripts/context/lua/mtx-update.lua index 581774f1e..d8a838fec 100644 --- a/scripts/context/lua/mtx-update.lua +++ b/scripts/context/lua/mtx-update.lua @@ -11,8 +11,6 @@ if not modules then modules = { } end modules ['mtx-update'] = { -- Together with Arthur Reutenauer she made sure that it worked well on all -- platforms that matter. -texmf.instance = instance -- we need to get rid of this / maybe current instance in global table - scripts = scripts or { } scripts.update = scripts.update or { } @@ -122,17 +120,23 @@ scripts.update.engines = { } scripts.update.platforms = { - ["mswin"] = "mswin", - ["windows"] = "mswin", - ["win32"] = "mswin", - ["win"] = "mswin", - ["linux"] = "linux", - ["freebsd"] = "freebsd", - ["linux-32"] = "linux", - ["linux-64"] = "linux-64", - ["osx"] = "osx-intel", - ["osx-intel"] = "osx-intel", - ["osx-ppc"] = "osx-ppc", + ["mswin"] = "mswin", + ["windows"] = "mswin", + ["win32"] = "mswin", + ["win"] = "mswin", + ["linux"] = "linux", + ["freebsd"] = "freebsd", + ["linux-32"] = "linux", + ["linux-64"] = "linux-64", + ["linux32"] = "linux", + ["linux64"] = "linux-64", + ["osx"] = "osx-intel", + ["osx-intel"] = "osx-intel", + ["osx-ppc"] = "osx-ppc", + ["osx-powerpc"] = "osx-ppc", + ["osxintel"] = "osx-intel", + ["osxppc"] = "osx-ppc", + ["osxpowerpc"] = "osx-ppc", } function scripts.update.run(str) @@ -185,7 +189,8 @@ function scripts.update.synchronize() local destination = string.format("%s/%s", texroot, collection[2]:gsub("<platform>", platform)) destination = destination:gsub("\\","/") archive = archive:gsub("<version>",version) - if platform == "windows" or platform == "mswin" then +--~ if platform == "windows" or platform == "mswin" then + if os.currentplatform() == "windows" or os.currentplatform() == "mswin" then destination = destination:gsub("([a-zA-Z]):/", "/cygdrive/%1/") end individual[#individual+1] = { archive, destination } diff --git a/scripts/context/lua/mtx-watch.lua b/scripts/context/lua/mtx-watch.lua index f9e81da42..a720fb47a 100644 --- a/scripts/context/lua/mtx-watch.lua +++ b/scripts/context/lua/mtx-watch.lua @@ -6,13 +6,30 @@ if not modules then modules = { } end modules ['mtx-watch'] = { license = "see context related readme files" } -texmf.instance = instance -- we need to get rid of this / maybe current instance in global table - scripts = scripts or { } scripts.watch = scripts.watch or { } do + function scripts.watch.save_exa_modes(modes,ctmname) + if modes then + local t= { } + t[#t+1] = "<?xml version='1.0' standalone='yes'?>\n" + t[#t+1] = "<exa:variables xmlns:exa='htpp://www.pragma-ade.com/schemas/exa-variables.rng'>" + if modes then + for k, v in ipairs(modes) do + local key, value = v:match("^(.*):([^:]-)$") + if key and value then + t[#t+1] = string.format("\t<exa:variable label='%s'>%s</exa:variable>",key,value) + end + end + end + t[#t+1] = "</exa:variables>" + os.remove(ctmname) + io.savedata(ctmname,table.concat(t,"\n")) + end + end + function scripts.watch.watch() local delay = environment.argument("delay") or 5 local logpath = environment.argument("logpath") or "" @@ -74,12 +91,17 @@ do local newpath = file.dirname(name) io.flush() local result = "" + local ctmname = file.basename(replacements.filename) + if ctmname == "" then ctmname = name end -- use self as fallback + ctmname = file.replacesuffix(ctmname,"ctm") if newpath ~= "" and newpath ~= "." then local oldpath = lfs.currentdir() lfs.chdir(newpath) + scripts.watch.save_exa_modes(joblog.modes,ctmname) if pipe then result = os.resultof(command) else result = os.spawn(command) end lfs.chdir(oldpath) else + scripts.watch.save_exa_modes(joblog.modes,ctmname) if pipe then result = os.resultof(command) else result = os.spawn(command) end end logs.report("watch",string.format("return value: %s", result)) diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index 040214178..45a881839 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -37,9 +37,10 @@ if not modules then modules = { } end modules ['mtxrun'] = { -- remember for subruns: _CTX_K_S_#{original}_ -- remember for subruns: TEXMFSTART.#{original} [tex.rb texmfstart.rb] -banner = "version 1.0.2 - 2007+ - PRAGMA ADE / CONTEXT" texlua = true +banner = "version 1.1.0 - 2007+ - PRAGMA ADE / CONTEXT" -- not local + -- begin library merge -- filename : l-string.lua -- comment : split off from luat-lib @@ -125,7 +126,7 @@ end function string:splitchr(chr) if #self > 0 then local t = { } - for s in string.gmatch(self..chr,"(.-)"..chr) do + for s in (self..chr):gmatch("(.-)"..chr) do t[#t+1] = s end return t @@ -134,22 +135,6 @@ function string:splitchr(chr) end end ---~ function string.piecewise(str, pat, fnc) -- variant of split ---~ local fpat = "(.-)"..pat ---~ local last_end = 1 ---~ local s, e, cap = string.find(str, fpat, 1) ---~ while s ~= nil do ---~ if s~=1 or cap~="" then ---~ fnc(cap) ---~ end ---~ last_end = e+1 ---~ s, e, cap = string.find(str, fpat, last_end) ---~ end ---~ if last_end <= #str then ---~ fnc((string.sub(str,last_end))) ---~ end ---~ end - function string.piecewise(str, pat, fnc) -- variant of split for k in string.splitter(str,pat) do fnc(k) end end @@ -668,35 +653,283 @@ function table.starts_at(t) return ipairs(t,1)(t,0) end -do +--~ do + +--~ -- one of my first exercises in lua ... + +--~ table.serialize_functions = true +--~ table.serialize_compact = true +--~ table.serialize_inline = true + +--~ local function key(k,noquotes) +--~ if type(k) == "number" then -- or k:find("^%d+$") then +--~ return "["..k.."]" +--~ elseif noquotes and k:find("^%a[%a%d%_]*$") then +--~ return k +--~ else +--~ return '["'..k..'"]' +--~ end +--~ end + +--~ local function simple_table(t) +--~ if #t > 0 then +--~ local n = 0 +--~ for _,v in pairs(t) do +--~ n = n + 1 +--~ end +--~ if n == #t then +--~ local tt = { } +--~ for i=1,#t do +--~ local v = t[i] +--~ local tv = type(v) +--~ if tv == "number" or tv == "boolean" then +--~ tt[#tt+1] = tostring(v) +--~ elseif tv == "string" then +--~ tt[#tt+1] = ("%q"):format(v) +--~ else +--~ tt = nil +--~ break +--~ end +--~ end +--~ return tt +--~ end +--~ end +--~ return nil +--~ end + +--~ local function serialize(root,name,handle,depth,level,reduce,noquotes,indexed) +--~ handle = handle or print +--~ reduce = reduce or false +--~ if depth then +--~ depth = depth .. " " +--~ if indexed then +--~ handle(("%s{"):format(depth)) +--~ else +--~ handle(("%s%s={"):format(depth,key(name,noquotes))) +--~ end +--~ else +--~ depth = "" +--~ local tname = type(name) +--~ if tname == "string" then +--~ if name == "return" then +--~ handle("return {") +--~ else +--~ handle(name .. "={") +--~ end +--~ elseif tname == "number" then +--~ handle("[" .. name .. "]={") +--~ elseif tname == "boolean" then +--~ if name then +--~ handle("return {") +--~ else +--~ handle("{") +--~ end +--~ else +--~ handle("t={") +--~ end +--~ end +--~ if root and next(root) then +--~ local compact = table.serialize_compact +--~ local inline = compact and table.serialize_inline +--~ local first, last = nil, 0 -- #root cannot be trusted here +--~ if compact then +--~ for k,v in ipairs(root) do -- NOT: for k=1,#root do (we need to quit at nil) +--~ if not first then first = k end +--~ last = last + 1 +--~ end +--~ end +--~ for _,k in pairs(table.sortedkeys(root)) do +--~ local v = root[k] +--~ local t = type(v) +--~ if compact and first and type(k) == "number" and k >= first and k <= last then +--~ if t == "number" then +--~ handle(("%s %s,"):format(depth,v)) +--~ elseif t == "string" then +--~ if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then +--~ handle(("%s %s,"):format(depth,v)) +--~ else +--~ handle(("%s %q,"):format(depth,v)) +--~ end +--~ elseif t == "table" then +--~ if not next(v) then +--~ handle(("%s {},"):format(depth)) +--~ elseif inline then +--~ local st = simple_table(v) +--~ if st then +--~ handle(("%s { %s },"):format(depth,table.concat(st,", "))) +--~ else +--~ serialize(v,k,handle,depth,level+1,reduce,noquotes,true) +--~ end +--~ else +--~ serialize(v,k,handle,depth,level+1,reduce,noquotes,true) +--~ end +--~ elseif t == "boolean" then +--~ handle(("%s %s,"):format(depth,tostring(v))) +--~ elseif t == "function" then +--~ if table.serialize_functions then +--~ handle(('%s loadstring(%q),'):format(depth,string.dump(v))) +--~ else +--~ handle(('%s "function",'):format(depth)) +--~ end +--~ else +--~ handle(("%s %q,"):format(depth,tostring(v))) +--~ end +--~ elseif k == "__p__" then -- parent +--~ if false then +--~ handle(("%s __p__=nil,"):format(depth)) +--~ end +--~ elseif t == "number" then +--~ handle(("%s %s=%s,"):format(depth,key(k,noquotes),v)) +--~ elseif t == "string" then +--~ if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then +--~ handle(("%s %s=%s,"):format(depth,key(k,noquotes),v)) +--~ else +--~ handle(("%s %s=%q,"):format(depth,key(k,noquotes),v)) +--~ end +--~ elseif t == "table" then +--~ if not next(v) then +--~ handle(("%s %s={},"):format(depth,key(k,noquotes))) +--~ elseif inline then +--~ local st = simple_table(v) +--~ if st then +--~ handle(("%s %s={ %s },"):format(depth,key(k,noquotes),table.concat(st,", "))) +--~ else +--~ serialize(v,k,handle,depth,level+1,reduce,noquotes) +--~ end +--~ else +--~ serialize(v,k,handle,depth,level+1,reduce,noquotes) +--~ end +--~ elseif t == "boolean" then +--~ handle(("%s %s=%s,"):format(depth,key(k,noquotes),tostring(v))) +--~ elseif t == "function" then +--~ if table.serialize_functions then +--~ handle(('%s %s=loadstring(%q),'):format(depth,key(k,noquotes),string.dump(v))) +--~ else +--~ handle(('%s %s="function",'):format(depth,key(k,noquotes))) +--~ end +--~ else +--~ handle(("%s %s=%q,"):format(depth,key(k,noquotes),tostring(v))) +--~ -- handle(('%s %s=loadstring(%q),'):format(depth,key(k,noquotes),string.dump(function() return v end))) +--~ end +--~ end +--~ if level > 0 then +--~ handle(("%s},"):format(depth)) +--~ else +--~ handle(("%s}"):format(depth)) +--~ end +--~ else +--~ handle(("%s}"):format(depth)) +--~ end +--~ end + +--~ --~ name: +--~ --~ +--~ --~ true : return { } +--~ --~ false : { } +--~ --~ nil : t = { } +--~ --~ string : string = { } +--~ --~ 'return' : return { } +--~ --~ number : [number] = { } + +--~ function table.serialize(root,name,reduce,noquotes) +--~ local t = { } +--~ local function flush(s) +--~ t[#t+1] = s +--~ end +--~ serialize(root, name, flush, nil, 0, reduce, noquotes) +--~ return table.concat(t,"\n") +--~ end + +--~ function table.tohandle(handle,root,name,reduce,noquotes) +--~ serialize(root, name, handle, nil, 0, reduce, noquotes) +--~ end + +--~ -- sometimes tables are real use (zapfino extra pro is some 85M) in which +--~ -- case a stepwise serialization is nice; actually, we could consider: +--~ -- +--~ -- for line in table.serializer(root,name,reduce,noquotes) do +--~ -- ...(line) +--~ -- end +--~ -- +--~ -- so this is on the todo list + +--~ table.tofile_maxtab = 2*1024 + +--~ function table.tofile(filename,root,name,reduce,noquotes) +--~ local f = io.open(filename,'w') +--~ if f then +--~ local concat = table.concat +--~ local maxtab = table.tofile_maxtab +--~ if maxtab > 1 then +--~ local t = { } +--~ local function flush(s) +--~ t[#t+1] = s +--~ if #t > maxtab then +--~ f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice +--~ t = { } +--~ end +--~ end +--~ serialize(root, name, flush, nil, 0, reduce, noquotes) +--~ f:write(concat(t,"\n"),"\n") +--~ else +--~ local function flush(s) +--~ f:write(s,"\n") +--~ end +--~ serialize(root, name, flush, nil, 0, reduce, noquotes) +--~ end +--~ f:close() +--~ end +--~ end + +--~ end - -- one of my first exercises in lua ... - - -- 34.055.092 32.403.326 arabtype.tma - -- 1.620.614 1.513.863 lmroman10-italic.tma - -- 1.325.585 1.233.044 lmroman10-regular.tma - -- 1.248.157 1.158.903 lmsans10-regular.tma - -- 194.646 153.120 lmtypewriter10-regular.tma - -- 1.771.678 1.658.461 palatinosanscom-bold.tma - -- 1.695.251 1.584.491 palatinosanscom-regular.tma - -- 13.736.534 13.409.446 zapfinoextraltpro.tma - - -- 13.679.038 11.774.106 arabtype.tmc - -- 886.248 754.944 lmroman10-italic.tmc - -- 729.828 466.864 lmroman10-regular.tmc - -- 688.482 441.962 lmsans10-regular.tmc - -- 128.685 95.853 lmtypewriter10-regular.tmc - -- 715.929 582.985 palatinosanscom-bold.tmc - -- 669.942 540.126 palatinosanscom-regular.tmc - -- 1.560.588 1.317.000 zapfinoextraltpro.tmc +--~ t = { +--~ b = "123", +--~ a = "x", +--~ c = 1.23, +--~ d = "1.23", +--~ e = true, +--~ f = { +--~ d = "1.23", +--~ a = "x", +--~ b = "123", +--~ c = 1.23, +--~ e = true, +--~ f = { +--~ e = true, +--~ f = { +--~ e = true +--~ }, +--~ }, +--~ }, +--~ g = function() end +--~ } + +--~ print(table.serialize(t), "\n") +--~ print(table.serialize(t,"name"), "\n") +--~ print(table.serialize(t,false), "\n") +--~ print(table.serialize(t,true), "\n") +--~ print(table.serialize(t,"name",true), "\n") +--~ print(table.serialize(t,"name",true,true), "\n") + +do table.serialize_functions = true table.serialize_compact = true table.serialize_inline = true + local sortedkeys = table.sortedkeys + local format, concat = string.format, table.concat + local noquotes, hexify, handle, reduce, compact, inline, functions + local pairs, ipairs, type, next, tostring = pairs, ipairs, type, next, tostring + local function key(k) if type(k) == "number" then -- or k:find("^%d+$") then - return "["..k.."]" + if hexify then + return ("[0x%04X]"):format(k) + else + return "["..k.."]" + end elseif noquotes and k:find("^%a[%a%d%_]*$") then return k else @@ -715,7 +948,13 @@ do for i=1,#t do local v = t[i] local tv = type(v) - if tv == "number" or tv == "boolean" then + if tv == "number" then + if hexify then + tt[#tt+1] = ("0x%04X"):format(v) + else + tt[#tt+1] = tostring(v) + end + elseif tv == "boolean" then tt[#tt+1] = tostring(v) elseif tv == "string" then tt[#tt+1] = ("%q"):format(v) @@ -730,53 +969,38 @@ do return nil end - local function serialize(root,name,handle,depth,level,reduce,noquotes,indexed) - handle = handle or print - reduce = reduce or false - if depth then + local function do_serialize(root,name,depth,level,indexed) + if level > 0 then depth = depth .. " " if indexed then handle(("%s{"):format(depth)) - else + elseif name then handle(("%s%s={"):format(depth,key(name))) - end - else - depth = "" - local tname = type(name) - if tname == "string" then - if name == "return" then - handle("return {") - else - handle(name .. "={") - end - elseif tname == "number" then - handle("[" .. name .. "]={") - elseif tname == "boolean" then - if name then - handle("return {") - else - handle("{") - end else - handle("t={") + handle(("%s{"):format(depth)) end end if root and next(root) then - local compact = table.serialize_compact - local inline = compact and table.serialize_inline local first, last = nil, 0 -- #root cannot be trusted here if compact then - for k,v in ipairs(root) do -- NOT: for k=1,#root do (why) + for k,v in ipairs(root) do -- NOT: for k=1,#root do (we need to quit at nil) if not first then first = k end last = last + 1 end end - for _,k in pairs(table.sortedkeys(root)) do + --~ for _,k in pairs(sortedkeys(root)) do -- 1% faster: + local sk = sortedkeys(root) + for i=1,#sk do + local k = sk[i] local v = root[k] local t = type(v) if compact and first and type(k) == "number" and k >= first and k <= last then if t == "number" then - handle(("%s %s,"):format(depth,v)) + if hexify then + handle(("%s 0x%04X,"):format(depth,v)) + else + handle(("%s %s,"):format(depth,v)) + end elseif t == "string" then if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then handle(("%s %s,"):format(depth,v)) @@ -789,17 +1013,17 @@ do elseif inline then local st = simple_table(v) if st then - handle(("%s { %s },"):format(depth,table.concat(st,", "))) + handle(("%s { %s },"):format(depth,concat(st,", "))) else - serialize(v,k,handle,depth,level+1,reduce,noquotes,true) + do_serialize(v,k,depth,level+1,true) end else - serialize(v,k,handle,depth,level+1,reduce,noquotes,true) + do_serialize(v,k,depth,level+1,true) end elseif t == "boolean" then handle(("%s %s,"):format(depth,tostring(v))) elseif t == "function" then - if table.serialize_functions then + if functions then handle(('%s loadstring(%q),'):format(depth,string.dump(v))) else handle(('%s "function",'):format(depth)) @@ -812,7 +1036,11 @@ do handle(("%s __p__=nil,"):format(depth)) end elseif t == "number" then - handle(("%s %s=%s,"):format(depth,key(k),v)) + if hexify then + handle(("%s %s=0x%04X,"):format(depth,key(k),v)) + else + handle(("%s %s=%s,"):format(depth,key(k),v)) + end elseif t == "string" then if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then handle(("%s %s=%s,"):format(depth,key(k),v)) @@ -825,17 +1053,17 @@ do elseif inline then local st = simple_table(v) if st then - handle(("%s %s={ %s },"):format(depth,key(k),table.concat(st,", "))) + handle(("%s %s={ %s },"):format(depth,key(k),concat(st,", "))) else - serialize(v,k,handle,depth,level+1,reduce,noquotes) + do_serialize(v,k,depth,level+1) end else - serialize(v,k,handle,depth,level+1,reduce,noquotes) + do_serialize(v,k,depth,level+1) end elseif t == "boolean" then handle(("%s %s=%s,"):format(depth,key(k),tostring(v))) elseif t == "function" then - if table.serialize_functions then + if functions then handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(v))) else handle(('%s %s="function",'):format(depth,key(k))) @@ -845,14 +1073,46 @@ do -- handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(function() return v end))) end end - if level > 0 then - handle(("%s},"):format(depth)) + end + if level > 0 then + handle(("%s},"):format(depth)) + end + end + + local function serialize(root,name,_handle,_reduce,_noquotes,_hexify) + noquotes = _noquotes + hexify = _hexify + handle = _handle or print + reduce = _reduce or false + compact = table.serialize_compact + inline = compact and table.serialize_inline + functions = table.serialize_functions + local tname = type(name) + if tname == "string" then + if name == "return" then + handle("return {") + else + handle(name .. "={") + end + elseif tname == "number" then + if hexify then + handle(format("[0x%04X]={",name)) + else + handle("[" .. name .. "]={") + end + elseif tname == "boolean" then + if name then + handle("return {") else - handle(("%s}"):format(depth)) + handle("{") end else - handle(("%s}"):format(depth)) + handle("t={") + end + if root and next(root) then + do_serialize(root,name,"",0,indexed) end + handle("}") end --~ name: @@ -864,17 +1124,17 @@ do --~ 'return' : return { } --~ number : [number] = { } - function table.serialize(root,name,reduce,noquotes) + function table.serialize(root,name,reduce,noquotes,hexify) local t = { } local function flush(s) t[#t+1] = s end - serialize(root, name, flush, nil, 0, reduce, noquotes) - return table.concat(t,"\n") + serialize(root,name,flush,reduce,noquotes,hexify) + return concat(t,"\n") end - function table.tohandle(handle,root,name,reduce,noquotes) - serialize(root, name, handle, nil, 0, reduce, noquotes) + function table.tohandle(handle,root,name,reduce,noquotes,hexify) + serialize(root,name,handle,reduce,noquotes,hexify) end -- sometimes tables are real use (zapfino extra pro is some 85M) in which @@ -888,10 +1148,9 @@ do table.tofile_maxtab = 2*1024 - function table.tofile(filename,root,name,reduce,noquotes) + function table.tofile(filename,root,name,reduce,noquotes,hexify) local f = io.open(filename,'w') if f then - local concat = table.concat local maxtab = table.tofile_maxtab if maxtab > 1 then local t = { } @@ -902,13 +1161,13 @@ do t = { } end end - serialize(root, name, flush, nil, 0, reduce, noquotes) + serialize(root,name,flush,reduce,noquotes,hexify) f:write(concat(t,"\n"),"\n") else local function flush(s) f:write(s,"\n") end - serialize(root, name, flush, nil, 0, reduce, noquotes) + serialize(root,name,flush,reduce,noquotes,hexify) end f:close() end @@ -916,35 +1175,6 @@ do end ---~ t = { ---~ b = "123", ---~ a = "x", ---~ c = 1.23, ---~ d = "1.23", ---~ e = true, ---~ f = { ---~ d = "1.23", ---~ a = "x", ---~ b = "123", ---~ c = 1.23, ---~ e = true, ---~ f = { ---~ e = true, ---~ f = { ---~ e = true ---~ }, ---~ }, ---~ }, ---~ g = function() end ---~ } - ---~ print(table.serialize(t), "\n") ---~ print(table.serialize(t,"name"), "\n") ---~ print(table.serialize(t,false), "\n") ---~ print(table.serialize(t,true), "\n") ---~ print(table.serialize(t,"name",true), "\n") ---~ print(table.serialize(t,"name",true,true), "\n") - do local function flatten(t,f,complete) @@ -1135,7 +1365,7 @@ function io.loaddata(filename) end function io.savedata(filename,data,joiner) - local f = io.open(filename, "wb") + local f = io.open(filename,"wb") if f then if type(data) == "table" then f:write(table.join(data,joiner or "")) @@ -1145,6 +1375,9 @@ function io.savedata(filename,data,joiner) f:write(data) end f:close() + return true + else + return false end end @@ -1499,6 +1732,9 @@ end -- copyright: PRAGMA ADE / ConTeXt Development Team -- license : see context related readme files + +--~ print(table.serialize(os.uname())) + if not versions then versions = { } end versions['l-os'] = 1.001 function os.resultof(command) @@ -1575,9 +1811,11 @@ if not versions then versions = { } end versions['l-file'] = 1.001 if not file then file = { } end function file.removesuffix(filename) - return filename:gsub("%.[%a%d]+$", "") + return (filename:gsub("%.[%a%d]+$","")) end +file.stripsuffix = file.removesuffix + function file.addsuffix(filename, suffix) if not filename:find("%.[%a%d]+$") then return filename .. "." .. suffix @@ -1587,11 +1825,7 @@ function file.addsuffix(filename, suffix) end function file.replacesuffix(filename, suffix) - if not filename:find("%.[%a%d]+$") then - return filename .. "." .. suffix - else - return (filename:gsub("%.[%a%d]+$","."..suffix)) - end + return (filename:gsub("%.[%a%d]+$","")) .. "." .. suffix end function file.dirname(name) @@ -1612,10 +1846,6 @@ end file.suffix = file.extname -function file.stripsuffix(name) - return (name:gsub("%.[%a%d]+$","")) -end - --~ function file.join(...) --~ local t = { ... } --~ for i=1,#t do @@ -1664,6 +1894,16 @@ function file.is_readable(name) end end +function file.iswritable(name) + local a = lfs.attributes(name) + return a and a.permissions:sub(2,2) == "w" +end + +function file.isreadable(name) + local a = lfs.attributes(name) + return a and a.permissions:sub(1,1) == "r" +end + --~ function file.split_path(str) --~ if str:find(';') then --~ return str:splitchr(";") @@ -1691,34 +1931,26 @@ function file.join_path(tab) return table.concat(tab,io.pathseparator) -- can have trailing // end ---~ print('test' .. " == " .. file.collapse_path("test")) ---~ print("test/test" .. " == " .. file.collapse_path("test/test")) ---~ print("test/test/test" .. " == " .. file.collapse_path("test/test/test")) ---~ print("test/test" .. " == " .. file.collapse_path("test/../test/test")) ---~ print("test" .. " == " .. file.collapse_path("test/../test")) ---~ print("../test" .. " == " .. file.collapse_path("../test")) ---~ 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 n = 1 - while n > 0 do - str, n = str:gsub("([^/%.]+/%.%./)","") - end - return (str:gsub("/%./","/")) -end + str = str:gsub("/%./","/") + local n, m = 1, 1 + while n > 0 or m > 0 do + str, n = str:gsub("[^/%.]+/%.%.$","") + str, m = str:gsub("[^/%.]+/%.%./","") + end + str = str:gsub("([^/])/$","%1") + str = str:gsub("^%./","") + str = str:gsub("/%.$","") + if str == "" then str = "." end + return str +end + +--~ print(file.collapse_path("a/./b/..")) +--~ print(file.collapse_path("a/aa/../b/bb")) +--~ print(file.collapse_path("a/../..")) +--~ print(file.collapse_path("a/.././././b/..")) +--~ print(file.collapse_path("a/./././b/..")) +--~ print(file.collapse_path("a/b/c/../..")) function file.robustname(str) return (str:gsub("[^%a%d%/%-%.\\]+","-")) @@ -1731,6 +1963,98 @@ function file.copy(oldname,newname) file.savedata(newname,io.loaddata(oldname)) end +-- lpeg variants, slightly faster, not always + +--~ local period = lpeg.P(".") +--~ local slashes = lpeg.S("\\/") +--~ local noperiod = 1-period +--~ local noslashes = 1-slashes +--~ local name = noperiod^1 + +--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.C(noperiod^1) * -1 + +--~ function file.extname(name) +--~ return pattern:match(name) or "" +--~ end + +--~ local pattern = lpeg.Cs(((period * noperiod^1 * -1)/"" + 1)^1) + +--~ function file.removesuffix(name) +--~ return pattern:match(name) +--~ end + +--~ file.stripsuffix = file.removesuffix + +--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1 + +--~ function file.basename(name) +--~ return pattern:match(name) or name +--~ end + +--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.Cp() * noslashes^1 * -1 + +--~ function file.dirname(name) +--~ local p = pattern:match(name) +--~ if p then +--~ return name:sub(1,p-2) +--~ else +--~ return "" +--~ end +--~ end + +--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1 + +--~ function file.addsuffix(name, suffix) +--~ local p = pattern:match(name) +--~ if p then +--~ return name +--~ else +--~ return name .. "." .. suffix +--~ end +--~ end + +--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1 + +--~ function file.replacesuffix(name,suffix) +--~ local p = pattern:match(name) +--~ if p then +--~ return name:sub(1,p-2) .. "." .. suffix +--~ else +--~ return name .. "." .. suffix +--~ end +--~ end + +--~ local pattern = (noslashes^0 * slashes)^0 * lpeg.Cp() * ((noperiod^1 * period)^1 * lpeg.Cp() + lpeg.P(true)) * noperiod^1 * -1 + +--~ function file.nameonly(name) +--~ local a, b = pattern:match(name) +--~ if b then +--~ return name:sub(a,b-2) +--~ elseif a then +--~ return name:sub(a) +--~ else +--~ return name +--~ end +--~ end + +--~ local test = file.extname +--~ local test = file.stripsuffix +--~ local test = file.basename +--~ local test = file.dirname +--~ local test = file.addsuffix +--~ local test = file.replacesuffix +--~ local test = file.nameonly + +--~ print(1,test("./a/b/c/abd.def.xxx","!!!")) +--~ print(2,test("./../b/c/abd.def.xxx","!!!")) +--~ print(3,test("a/b/c/abd.def.xxx","!!!")) +--~ print(4,test("a/b/c/def.xxx","!!!")) +--~ print(5,test("a/b/c/def","!!!")) +--~ print(6,test("def","!!!")) +--~ print(7,test("def.xxx","!!!")) + +--~ local tim = os.clock() for i=1,250000 do local ext = test("abd.def.xxx","!!!") end print(os.clock()-tim) + -- filename : l-dir.lua -- comment : split off from luat-lib @@ -1746,51 +2070,6 @@ dir = { } if lfs then do ---~ local attributes = lfs.attributes ---~ local walkdir = lfs.dir ---~ ---~ local function glob_pattern(path,patt,recurse,action) ---~ local ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe ---~ if ok and type(scanner) == "function" then ---~ if not path:find("/$") then path = path .. '/' end ---~ for name in scanner do ---~ local full = path .. name ---~ local mode = attributes(full,'mode') ---~ if mode == 'file' then ---~ if name:find(patt) then ---~ action(full) ---~ end ---~ elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then ---~ glob_pattern(full,patt,recurse,action) ---~ end ---~ end ---~ end ---~ end ---~ ---~ dir.glob_pattern = glob_pattern ---~ ---~ local function glob(pattern, action) ---~ local t = { } ---~ local action = action or function(name) t[#t+1] = name end ---~ local path, patt = pattern:match("^(.*)/*%*%*/*(.-)$") ---~ local recurse = path and patt ---~ if not recurse then ---~ path, patt = pattern:match("^(.*)/(.-)$") ---~ if not (path and patt) then ---~ path, patt = '.', pattern ---~ end ---~ end ---~ patt = patt:gsub("([%.%-%+])", "%%%1") ---~ patt = patt:gsub("%*", ".*") ---~ patt = patt:gsub("%?", ".") ---~ patt = "^" .. patt .. "$" ---~ -- print('path: ' .. path .. ' | pattern: ' .. patt .. ' | recurse: ' .. tostring(recurse)) ---~ glob_pattern(path,patt,recurse,action) ---~ return t ---~ end ---~ ---~ dir.glob = glob - local attributes = lfs.attributes local walkdir = lfs.dir @@ -1868,13 +2147,17 @@ if lfs then do glob(s,t) end return t + elseif lfs.isfile(str) then + local t = t or { } + t[#t+1] = str + return t else local split = pattern:match(str) if split then local t = t or { } local action = action or function(name) t[#t+1] = name end local root, path, base = split[1], split[2], split[3] - local recurse = base:find("**") + local recurse = base:find("%*%*") local start = root .. path local result = filter:match(start .. base) glob_pattern(start,result,recurse,action) @@ -1902,16 +2185,21 @@ if lfs then do for name in walkdir(path) do if name:find("^%.") then --- skip - elseif attributes(name,'mode') == "directory" then - if recurse then - globfiles(path .. "/" .. name,recurse,func,files) - end - elseif func then - if func(name) then - files[#files+1] = path .. "/" .. name - end else - files[#files+1] = path .. "/" .. name + local mode = attributes(name,'mode') + if mode == "directory" then + if recurse then + globfiles(path .. "/" .. name,recurse,func,files) + end + elseif mode == "file" then + if func then + if func(name) then + files[#files+1] = path .. "/" .. name + end + else + files[#files+1] = path .. "/" .. name + end + end end end return files @@ -2119,7 +2407,7 @@ function toboolean(str,tolerant) if tolerant then local tstr = type(str) if tstr == "string" then - return str == "true" or str == "yes" or str == "on" or str == "1" + return str == "true" or str == "yes" or str == "on" or str == "1" or str == "t" elseif tstr == "number" then return tonumber(str) ~= 0 elseif tstr == "nil" then @@ -2138,9 +2426,9 @@ end function string.is_boolean(str) if type(str) == "string" then - if str == "true" or str == "yes" or str == "on" then + if str == "true" or str == "yes" or str == "on" or str == "t" then return true - elseif str == "false" or str == "no" or str == "off" then + elseif str == "false" or str == "no" or str == "off" or str == "f" then return false end end @@ -2364,7 +2652,7 @@ do end dt = top.dt dt[#dt+1] = toclose - if at.xmlns then + if toclose.at.xmlns then remove(xmlns) end end @@ -2378,10 +2666,10 @@ do local t = { ns=namespace or "", rn=resolved, tg=tag, at=at, dt={}, __p__ = top } dt[#dt+1] = t setmetatable(t, mt) - at = { } if at.xmlns then remove(xmlns) end + at = { } end local function add_text(text) if cleanup and #text > 0 then @@ -2638,22 +2926,19 @@ 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 - + if e.special then + local etg, edt = e.tg, e.dt + local spc = specialconverter and specialconverter[etg] + if spc then + 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) @@ -2704,17 +2989,7 @@ end end 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 + ens = ern end if ens ~= "" then if edt and #edt > 0 then @@ -2758,7 +3033,16 @@ ens = ern handle("<" .. etg .. ">") end for i=1,#edt do - serialize(edt[i],handle,textconverter,attributeconverter,specialconverter,nocommands) + local ei = edt[i] + if type(ei) == "string" then + if textconverter then + handle(textconverter(ei)) + else + handle(ei) + end + else + serialize(ei,handle,textconverter,attributeconverter,specialconverter,nocommands) + end end -- handle(format("</%s>",etg)) handle("</" .. etg .. ">") @@ -2781,7 +3065,16 @@ ens = ern end else for i=1,#e do - serialize(e[i],handle,textconverter,attributeconverter,specialconverter,nocommands) + local ei = e[i] + if type(ei) == "string" then + if textconverter then + handle(textconverter(ei)) + else + handle(ei) + end + else + serialize(ei,handle,textconverter,attributeconverter,specialconverter,nocommands) + end end end end @@ -2811,14 +3104,14 @@ ens = ern function xml.tostring(root) -- 25% overhead due to collecting if root then - if type(root) == 'string' then - return root - elseif next(root) then -- next is faster than type (and >0 test) - local result = { } - serialize(root,function(s) result[#result+1] = s end) - return concat(result,"") + if type(root) == 'string' then + return root + elseif next(root) then -- next is faster than type (and >0 test) + local result = { } + serialize(root,function(s) result[#result+1] = s end) + return concat(result,"") + end end - end return "" end @@ -2883,6 +3176,18 @@ function xml.content(root) -- bugged return (root and root.dt and xml.tostring(root.dt)) or "" end +function xml.isempty(root, pattern) + if pattern == "" or pattern == "*" then + pattern = nil + end + if pattern then + -- todo + return false + else + return not root or not root.dt or #root.dt == 0 or root.dt == "" + end +end + --[[ldx-- <p>The next helper erases an element but keeps the table as it is, and since empty strings are not serialized (effectively) it does @@ -2925,6 +3230,9 @@ of <l n='xpath'/> and since we're not compatible we call it <l n='lpath'/>. We will explain more about its usage in other documents.</p> --ldx]]-- +local lpathcalls = 0 -- statisctics +local lpathcached = 0 -- statisctics + do xml.functions = xml.functions or { } @@ -3184,11 +3492,13 @@ do local cache = { } function xml.lpath(pattern,trace) + lpathcalls = lpathcalls + 1 if type(pattern) == "string" then local result = cache[pattern] - if not result then + if result == nil then -- can be false which is valid -) result = compose(pattern) cache[pattern] = result + lpathcached = lpathcached + 1 end if trace or xml.trace_lpath then xml.lshow(result) @@ -3199,6 +3509,10 @@ do end end + function lpath_cached_patterns() + return cache + end + local fallbackreport = (texio and texio.write) or io.write function xml.lshow(pattern,report) @@ -3291,35 +3605,20 @@ do return (rdt and rdt[k]) or root[k] or "" end end - functions.name = function(root,k,n) - -- way too fuzzy - local found - if not k or not n then - local ns, tg = root.rn or root.ns or "", root.tg - if not tg then - for i=1,#root do - local e = root[i] - if type(e) == "table" then - found = e - break - end - end - elseif ns ~= "" then - return ns .. ":" .. tg - else - return tg - end + functions.name = function(d,k,n) -- ns + tg + local found = false + n = n or 0 + if not k then + -- not found elseif n == 0 then - local e = root[k] - if type(e) ~= "table" then - found = e - end + local dk = d[k] + found = dk and (type(dk) == "table") and dk elseif n < 0 then for i=k-1,1,-1 do - local e = root[i] - if type(e) == "table" then + local di = d[i] + if type(di) == "table" then if n == -1 then - found = e + found = di break else n = n + 1 @@ -3327,12 +3626,11 @@ do end end else ---~ print(k,n,#root) - for i=k+1,#root,1 do - local e = root[i] - if type(e) == "table" then + for i=k+1,#d,1 do + local di = d[i] + if type(di) == "table" then if n == 1 then - found = e + found = di break else n = n - 1 @@ -3351,6 +3649,41 @@ do return "" end end + functions.tag = function(d,k,n) -- only tg + local found = false + n = n or 0 + if not k then + -- not found + elseif n == 0 then + local dk = d[k] + found = dk and (type(dk) == "table") and dk + elseif n < 0 then + for i=k-1,1,-1 do + local di = d[i] + if type(di) == "table" then + if n == -1 then + found = di + break + else + n = n + 1 + end + end + end + else + for i=k+1,#d,1 do + local di = d[i] + if type(di) == "table" then + if n == 1 then + found = di + break + else + n = n - 1 + end + end + end + end + return (found and found.tg) or "" + end local function traverse(root,pattern,handle,reverse,index,parent,wildcard) -- multiple only for tags, not for namespaces if not root then -- error @@ -4116,15 +4449,20 @@ do xml.each_element(xmldata, pattern, include) end - function xml.strip_whitespace(root, pattern) + function xml.strip_whitespace(root, pattern) -- strips all leading and trailing space ! traverse(root, lpath(pattern), function(r,d,k) local dkdt = d[k].dt if dkdt then -- can be optimized local t = { } for i=1,#dkdt do local str = dkdt[i] - if type(str) == "string" and str:find("^[ \n\r\t]*$") then - -- stripped + if type(str) == "string" then + str = str:gsub("^[ \n\r\t]*(.-)[ \n\r\t]*$","%1") + if str == "" then + -- stripped + else + t[#t+1] = str + end else t[#t+1] = str end @@ -4326,9 +4664,9 @@ original entity is returned.</p> do if unicode and unicode.utf8 then - xml.entities = xml.entities or { } -- xml.entities.handler == function + xml.entities = xml.entities or { } -- xml.entity_handler == function - function xml.entities.handler(e) + function xml.entity_handler(e) return format("[%s]",e) end @@ -4338,8 +4676,6 @@ 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 @@ -4361,11 +4697,11 @@ do if unicode and unicode.utf8 then if e:find("#x") then return char(tonumber(e:sub(3),16)) else - local ee = entities[e] + local ee = xml.entities[e] -- we cannot shortcut this one (is reloaded) if ee then return ee else - local h = xml.entities.handler + local h = xml.entity_handler return (h and h(e)) or "&" .. e .. ";" end end @@ -4427,6 +4763,13 @@ do if unicode and unicode.utf8 then end end +function xml.statistics() + return { + lpathcalls = lpathcalls, + lpathcached = lpathcached, + } +end + -- xml.set_text_cleanup(xml.show_text_entities) -- xml.set_text_cleanup(xml.resolve_text_entities) @@ -4505,12 +4848,18 @@ function utils.report(...) print(...) end +utils.merger.strip_comment = true + function utils.merger._self_load_(name) local f, data = io.open(name), "" if f then data = f:read("*all") f:close() end + if data and utils.merger.strip_comment then + -- saves some 20K + data = data:gsub("%-%-~[^\n\r]*[\r\n]", "") + end return data or "" end @@ -4588,108 +4937,62 @@ function utils.merger.selfclean(name) ) end -utils.lua.compile_strip = true - -function utils.lua.compile(luafile, lucfile) +function utils.lua.compile(luafile, lucfile, cleanup, strip) -- defaults: cleanup=false strip=true -- utils.report("compiling",luafile,"into",lucfile) os.remove(lucfile) local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile) - if utils.lua.compile_strip then + if strip ~= false 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 == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then + -- utils.report("removing",luafile) + os.remove(luafile) end + return done end --- filename : luat-lib.lua --- comment : companion to luat-lib.tex --- author : Hans Hagen, PRAGMA-ADE, Hasselt NL --- copyright: PRAGMA ADE / ConTeXt Development Team --- license : see context related readme files - -if not versions then versions = { } end versions['luat-lib'] = 1.001 - --- mostcode moved to the l-*.lua and other luat-*.lua files +if not modules then modules = { } end modules ['luat-lib'] = { + version = 1.001, + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", + comment = "companion to luat-lib.tex", +} --- os / io +-- most code already moved to the l-*.lua and other luat-*.lua files os.setlocale(nil,nil) -- useless feature and even dangerous in luatex --- os.platform - --- mswin|bccwin|mingw|cygwin windows --- darwin|rhapsody|nextstep macosx --- netbsd|unix unix --- linux linux - -if not io.fileseparator then - if string.find(os.getenv("PATH"),";") then - io.fileseparator, io.pathseparator, os.platform = "\\", ";", os.type or "windows" - else - io.fileseparator, io.pathseparator, os.platform = "/" , ":", os.type or "unix" - end -end - -os.platform = os.platform or os.type or (io.pathseparator == ";" and "windows") or "unix" - --- arg normalization --- --- for k,v in pairs(arg) do print(k,v) 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 +function os.setlocale() + -- no way you can mess with it 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 - -environment.platform = os.platform +environment = environment or { } +environment.arguments = { } +environment.files = { } +environment.sortedflags = nil function environment.initialize_arguments(arg) - environment.arguments = { } - environment.files = { } - environment.sorted_argument_keys = nil + local arguments, files = { }, { } + environment.arguments, environment.files, environment.sortedflags = arguments, files, nil for index, argument in pairs(arg) do if index > 0 then local flag, value = argument:match("^%-+(.+)=(.-)$") if flag then - environment.arguments[flag] = string.unquote(value or "") + arguments[flag] = string.unquote(value or "") else flag = argument:match("^%-+(.+)") if flag then - environment.arguments[flag] = true + arguments[flag] = true else - environment.files[#environment.files+1] = argument + files[#files+1] = argument end end end @@ -4711,18 +5014,20 @@ function environment.setargument(name,value) end function environment.argument(name) - if environment.arguments[name] then - return environment.arguments[name] + local arguments, sortedflags = environment.arguments, environment.sortedflags + if arguments[name] then + return arguments[name] else - if not environment.sorted_argument_keys then - environment.sorted_argument_keys = { } - for _,v in pairs(table.sortedkeys(environment.arguments)) do - table.insert(environment.sorted_argument_keys, "^" .. v) + if not sortedflags then + sortedflags = { } + for _,v in pairs(table.sortedkeys(arguments)) do + sortedflags[#sortedflags+1] = "^" .. v end + environment.sortedflags = sortedflags end - for _,v in pairs(environment.sorted_argument_keys) do + for _,v in ipairs(sortedflags) do if name:find(v) then - return environment.arguments[v:sub(2,#v)] + return arguments[v:sub(2,#v)] end end end @@ -4770,21 +5075,24 @@ if arg then end --- filename : luat-inp.lua --- comment : companion to luat-lib.tex --- author : Hans Hagen, PRAGMA-ADE, Hasselt NL --- copyright: PRAGMA ADE / ConTeXt Development Team --- license : see context related readme files - --- This lib is multi-purpose and can be loaded again later on so that --- additional functionality becomes available. We will split this --- module in components when we're done with prototyping. +if not modules then modules = { } end modules ['luat-inp'] = { + version = 1.001, + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", + comment = "companion to luat-lib.tex", +} -- 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. +-- This lib is multi-purpose and can be loaded again later on so that +-- additional functionality becomes available. We will split this +-- module in components once we're done with prototyping. This is the +-- first code I wrote for LuaTeX, so it needs some cleanup. Before changing +-- something in this module one can best check with Taco or Hans first; there +-- is some nasty trickery going on that relates to traditional kpse support. -- To be considered: hash key lowercase, first entry in table filename -- (any case), rest paths (so no need for optimization). Or maybe a @@ -4794,12 +5102,6 @@ end -- Beware, loading and saving is overloaded in luat-tmp! -if not versions then versions = { } end versions['luat-inp'] = 1.001 -if not environment then environment = { } end -if not file then file = { } end - -if environment.aleph_mode == nil then environment.aleph_mode = true end -- temp hack - if not input then input = { } end if not input.suffixes then input.suffixes = { } end if not input.formats then input.formats = { } end @@ -4825,8 +5127,16 @@ input.debug = false input.cnfname = 'texmf.cnf' input.luaname = 'texmfcnf.lua' input.lsrname = 'ls-R' -input.luasuffix = '.tma' -input.lucsuffix = '.tmc' +input.homedir = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~' + +--~ input.luasuffix = 'tma' +--~ input.lucsuffix = 'tmc' + +-- for the moment we have .local but this will disappear +input.cnfdefault = '{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}' + +-- chances are low that the cnf file is in the bin path +input.cnfdefault = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}' -- we use a cleaned up list / format=any is a wildcard, as is *name @@ -4862,7 +5172,8 @@ input.suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' } -- FONTFEATURES = .;$TEXMF/fonts/fea// -- FONTCIDMAPS = .;$TEXMF/fonts/cid// -function input.checkconfigdata(instance) -- not yet ok, no time for debugging now +function input.checkconfigdata() -- not yet ok, no time for debugging now + local instance = input.instance local function fix(varname,default) local proname = varname .. "." .. instance.progname or "crap" local p = instance.environment[proname] @@ -4871,7 +5182,15 @@ function input.checkconfigdata(instance) -- not yet ok, no time for debugging no instance.variables[varname] = default -- or environment? end end - fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") + local name = os.name + if name == "windows" then + fix("OSFONTDIR", "c:/windows/fonts//") + elseif name == "macosx" then + fix("OSFONTDIR", "$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//") + else + -- bad luck + end + fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") end @@ -4898,14 +5217,20 @@ input.formats ['sfd'] = 'SFDFONTS' input.suffixes ['sfd'] = { 'sfd' } input.alternatives['subfont definition files'] = 'sfd' -function input.reset() +-- In practice we will work within one tds tree, but i want to keep +-- the option open to build tools that look at multiple trees, which is +-- why we keep the tree specific data in a table. We used to pass the +-- instance but for practical pusposes we now avoid this and use a +-- instance variable. + +function input.newinstance() local instance = { } instance.rootpath = '' instance.treepath = '' - instance.progname = environment.progname or 'context' - instance.engine = environment.engine or 'luatex' + instance.progname = 'context' + instance.engine = 'luatex' instance.format = '' instance.environment = { } instance.variables = { } @@ -4929,12 +5254,12 @@ function input.reset() instance.cachepath = nil instance.loaderror = false instance.smallcache = false + instance.sortdata = false instance.savelists = true instance.cleanuppaths = true instance.allresults = false instance.pattern = nil -- lists instance.kpseonly = false -- lists - instance.cachefile = 'tmftools' instance.loadtime = 0 instance.starttime = 0 instance.stoptime = 0 @@ -4945,23 +5270,13 @@ function input.reset() instance.fakepaths = { } instance.lsrmode = false - if os.env then - -- store once, freeze and faster - for k,v in pairs(os.env) do - instance.environment[k] = input.bare_variable(v) - end - else - -- we will access os.env frequently - 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)) - instance.environment[v] = input.bare_variable(e) - end - end + -- store once, freeze and faster (once reset we can best use instance.environment) + + for k,v in pairs(os.env) do + instance.environment[k] = input.bare_variable(v) end - -- cross referencing + -- cross referencing, delayed because we can add suffixes for k, v in pairs(input.suffixes) do for _, vv in pairs(v) do @@ -4975,68 +5290,42 @@ function input.reset() end -function input.reset_hashes(instance) - instance.lists = { } - instance.found = { } -end - -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 +input.instance = input.instance or nil -if texio then - input.log = texio.write_nl -else - input.log = print +function input.reset() + input.instance = input.newinstance() + return input.instance end -function input.simple_logger(kind, name) - if name and name ~= "" then - if input.banner then - input.log(input.banner..kind..": "..name) - else - input.log("<<"..kind..": "..name..">>") - end - else - if input.banner then - input.log(input.banner..kind..": no name") - else - input.log("<<"..kind..": no name>>") - end - end +function input.reset_hashes() + input.instance.lists = { } + input.instance.found = { } end -function input.dummy_logger() +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 function input.settrace(n) input.trace = tonumber(n or 0) if input.trace > 0 then - input.logger = input.simple_logger input.verbose = true - else - input.logger = function() end end end -function input.report(...) -- inefficient +input.log = (texio and texio.write_nl) or print + +function input.report(...) if input.verbose then - if input.banner then - input.log(input.banner .. table.concat({...},' ')) - elseif input.logmode() == 'xml' then - input.log("<t>"..table.concat({...},' ').."</t>") - else - input.log("<<"..table.concat({...},' ')..">>") - end + input.log("<<"..format(...)..">>") end end -function input.reportlines(str) - if type(str) == "string" then - str = str:split("\n") +function input.report(...) + if input.trace > 0 then -- extra test + input.log("<<"..format(...)..">>") end - for _,v in pairs(str) do input.report(v) end end input.settrace(tonumber(os.getenv("MTX.INPUT.TRACE") or os.getenv("MTX_INPUT_TRACE") or input.trace or 0)) @@ -5065,7 +5354,7 @@ do instance.stoptime = stoptime instance.loadtime = instance.loadtime + loadtime if report then - input.report('load time', format("%0.3f",loadtime)) + input.report("load time %0.3f",loadtime) end return loadtime end @@ -5081,18 +5370,18 @@ end function input.report_loadtime(instance) if instance then - input.report('total load time', input.elapsedtime(instance)) + input.report('total load time %s', input.elapsedtime(instance)) end end input.loadtime = input.elapsedtime -function input.env(instance,key) - return instance.environment[key] or input.osenv(instance,key) +function input.env(key) + return input.instance.environment[key] or input.osenv(key) end -function input.osenv(instance,key) - local ie = instance.environment +function input.osenv(key) + local ie = input.instance.environment local value = ie[key] if value == nil then -- local e = os.getenv(key) @@ -5110,81 +5399,106 @@ end -- we follow a rather traditional approach: -- -- (1) texmf.cnf given in TEXMFCNF --- (2) texmf.cnf searched in TEXMF/web2c +-- (2) texmf.cnf searched in default variable -- --- for the moment we don't expect a configuration file in a zip +-- also we now follow the stupid route: if not set then just assume *one* +-- cnf file under texmf (i.e. distribution) -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 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 +input.ownpath = input.ownpath or nil +input.ownbin = input.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex" +input.autoselfdir = true -- false may be handy for debugging + +function input.getownpath() + if not input.ownpath then + if input.autoselfdir and os.selfdir then + input.ownpath = os.selfdir + else + local binary = input.ownbin + if os.platform == "windows" then + binary = file.replacesuffix(binary,"exe") + end + for p in string.gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do + local b = file.join(p,binary) + if lfs.isfile(b) then + -- we assume that after changing to the path the currentdir function + -- resolves to the real location and use this side effect here; this + -- trick is needed because on the mac installations use symlinks in the + -- path instead of real locations + local olddir = lfs.currentdir() + if lfs.chdir(p) then + local pp = lfs.currentdir() + if input.verbose and p ~= pp then + input.report("following symlink %s to %s",p,pp) 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 + input.ownpath = pp + lfs.chdir(olddir) + else + if input.verbose then + input.report("unable to check path %s",p) end + input.ownpath = p 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() + break 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 - else - local t = input.split_path(input.env(instance,'TEXMFCNF')) - t = input.aux.expanded_path(instance,t) - input.aux.expand_vars(instance,t) - 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 + if not input.ownpath then input.ownpath = '.' end + end + return input.ownpath +end + +function input.identify_own() + local instance = input.instance + local ownpath = input.getownpath() or lfs.currentdir() + local ie = instance.environment + if ownpath then + if input.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end + if input.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end + if input.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end + else + input.verbose = true + input.report("error: unable to locate ownpath") + os.exit() + end + if input.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = input.cnfdefault end + if input.env('TEXOS') == "" then os.env['TEXOS'] = input.env('SELFAUTODIR') end + if input.env('TEXROOT') == "" then os.env['TEXROOT'] = input.env('SELFAUTOPARENT') end + if input.verbose then + for _,v in ipairs({"SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF"}) do + input.report("variable %s set to %s",v,input.env(v) or "unknown") + end + end + function input.identify_own() end +end + +function input.identify_cnf() + local instance = input.instance + if #instance.cnffiles == 0 then + -- fallback + input.identify_own() + -- the real search + input.expand_variables() + local t = input.split_path(input.env('TEXMFCNF')) + t = input.aux.expanded_path(t) + input.aux.expand_vars(t) -- redundant + 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 - locate(input.luaname,instance.luafiles) - locate(input.cnfname,instance.cnffiles) end + locate(input.luaname,instance.luafiles) + locate(input.cnfname,instance.cnffiles) end end -function input.load_cnf(instance) +function input.load_cnf() + local instance = input.instance local function loadoldconfigdata() for _, fname in ipairs(instance.cnffiles) do - input.aux.load_cnf(instance,fname) + input.aux.load_cnf(fname) end end -- instance.cnffiles contain complete names now ! @@ -5199,27 +5513,27 @@ function input.load_cnf(instance) 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 loadoldconfigdata() elseif instance.diskcache and not instance.renewcache then - input.loadoldconfig(instance,instance.cnffiles) + input.loadoldconfig(instance.cnffiles) if instance.loaderror then loadoldconfigdata() - input.saveoldconfig(instance) + input.saveoldconfig() end else loadoldconfigdata() if instance.renewcache then - input.saveoldconfig(instance) + input.saveoldconfig() end end - input.aux.collapse_cnf_data(instance) + input.aux.collapse_cnf_data() end - input.checkconfigdata(instance) + input.checkconfigdata() end -function input.load_lua(instance) +function input.load_lua() + local instance = input.instance if #instance.luafiles == 0 then -- yet harmless else @@ -5231,14 +5545,14 @@ function input.load_lua(instance) 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) + input.loadnewconfig() + input.aux.collapse_cnf_data() end - input.checkconfigdata(instance) + input.checkconfigdata() end -function input.aux.collapse_cnf_data(instance) -- potential optmization: pass start index (setup and configuration are shared) +function input.aux.collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared) + local instance = input.instance for _,c in ipairs(instance.order) do for k,v in pairs(c) do if not instance.variables[k] then @@ -5253,21 +5567,22 @@ function input.aux.collapse_cnf_data(instance) -- potential optmization: pass st end end -function input.aux.load_cnf(instance,fname) +function input.aux.load_cnf(fname) + local instance = input.instance fname = input.clean_path(fname) - local lname = fname:gsub("%.%a+$",input.luasuffix) + local lname = file.replacesuffix(fname,'lua') local f = io.open(lname) if f then -- this will go f:close() local dname = file.dirname(fname) if not instance.configuration[dname] then - input.aux.load_configuration(instance,dname,lname) + input.aux.load_configuration(dname,lname) instance.order[#instance.order+1] = instance.configuration[dname] end else f = io.open(fname) if f then - input.report("loading", fname) + input.report("loading %s", fname) local line, data, n, k, v local dname = file.dirname(fname) if not instance.configuration[dname] then @@ -5299,227 +5614,226 @@ function input.aux.load_cnf(instance,fname) end f:close() else - input.report("skipping", fname) + input.report("skipping %s", fname) end end end -- database loading -function input.load_hash(instance) - input.locatelists(instance) +function input.load_hash() + local instance = input.instance + input.locatelists() if instance.lsrmode then - input.loadlists(instance) + input.loadlists() elseif instance.diskcache and not instance.renewcache then - input.loadfiles(instance) + input.loadfiles() if instance.loaderror then - input.loadlists(instance) - input.savefiles(instance) + input.loadlists() + input.savefiles() end else - input.loadlists(instance) + input.loadlists() if instance.renewcache then - input.savefiles(instance) + input.savefiles() end end end -function input.aux.append_hash(instance,type,tag,name) - input.logger("= hash append",tag) - table.insert(instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } ) +function input.aux.append_hash(type,tag,name) + if input.trace > 0 then + input.logger("= hash append: %s",tag) + end + table.insert(input.instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } ) end -function input.aux.prepend_hash(instance,type,tag,name) - input.logger("= hash prepend",tag) - table.insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } ) +function input.aux.prepend_hash(type,tag,name) + if input.trace > 0 then + input.logger("= hash prepend: %s",tag) + end + table.insert(input.instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } ) end -function input.aux.extend_texmf_var(instance,specification) -- crap - if instance.environment['TEXMF'] then - input.report("extending environment variable TEXMF with", specification) - instance.environment['TEXMF'] = instance.environment['TEXMF']:gsub("^%{", function() - return "{" .. specification .. "," - end) - elseif instance.variables['TEXMF'] then - input.report("extending configuration variable TEXMF with", specification) - instance.variables['TEXMF'] = instance.variables['TEXMF']:gsub("^%{", function() - return "{" .. specification .. "," - end) +function input.aux.extend_texmf_var(specification) -- crap, we could better prepend the hash + local instance = input.instance +-- local t = input.expanded_path_list('TEXMF') -- full expansion + local t = input.split_path(input.env('TEXMF')) + table.insert(t,1,specification) + local newspec = table.join(t,";") + if instance.environment["TEXMF"] then + instance.environment["TEXMF"] = newspec + elseif instance.variables["TEXMF"] then + instance.variables["TEXMF"] = newspec else - input.report("setting configuration variable TEXMF to", specification) - instance.variables['TEXMF'] = "{" .. specification .. "}" - end - if instance.variables['TEXMF']:find("%,") and not instance.variables['TEXMF']:find("^%{") then - input.report("adding {} to complex TEXMF variable, best do that yourself") - instance.variables['TEXMF'] = "{" .. instance.variables['TEXMF'] .. "}" + -- weird end - input.expand_variables(instance) - input.reset_hashes(instance) + input.expand_variables() + input.reset_hashes() end -- locators -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)) +function input.locatelists() + local instance = input.instance + for _, path in pairs(input.clean_path_list('TEXMF')) do + input.report("locating list of %s",path) + input.locatedatabase(input.normalize_name(path)) end end -function input.locatedatabase(instance,specification) - return input.methodhandler('locators', instance, specification) +function input.locatedatabase(specification) + return input.methodhandler('locators', specification) end -function input.locators.tex(instance,specification) +function input.locators.tex(specification) if specification and specification ~= '' and lfs.isdir(specification) then - input.logger('! tex locator', specification..' found') - input.aux.append_hash(instance,'file',specification,filename) - else - input.logger('? tex locator', specification..' not found') + if input.trace > 0 then + input.logger('! tex locator found: %s',specification) + end + input.aux.append_hash('file',specification,filename) + elseif input.trace > 0 then + input.logger('? tex locator not found: %s',specification) end end -- hashers -function input.hashdatabase(instance,tag,name) - return input.methodhandler('hashers',instance,tag,name) +function input.hashdatabase(tag,name) + return input.methodhandler('hashers',tag,name) end -function input.loadfiles(instance) +function input.loadfiles() + local instance = input.instance instance.loaderror = false instance.files = { } if not instance.renewcache then for _, hash in ipairs(instance.hashes) do - input.hashdatabase(instance,hash.tag,hash.name) + input.hashdatabase(hash.tag,hash.name) if instance.loaderror then break end end end end -function input.hashers.tex(instance,tag,name) - input.aux.load_files(instance,tag) +function input.hashers.tex(tag,name) + input.aux.load_files(tag) end -- generators: -function input.loadlists(instance) - for _, hash in ipairs(instance.hashes) do - input.generatedatabase(instance,hash.tag) +function input.loadlists() + for _, hash in ipairs(input.instance.hashes) do + input.generatedatabase(hash.tag) end end -function input.generatedatabase(instance,specification) - return input.methodhandler('generators', instance, specification) +function input.generatedatabase(specification) + return input.methodhandler('generators', specification) end -do - - local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) +local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) - function input.generators.tex(instance,specification) - local tag = specification - if not instance.lsrmode and lfs and lfs.dir then - input.report("scanning path",specification) - instance.files[tag] = { } - local files = instance.files[tag] - local n, m, r = 0, 0, 0 - local spec = specification .. '/' - local attributes = lfs.attributes - local directory = lfs.dir - local small = instance.smallcache - local function action(path) - local mode, full - if path then - full = spec .. path .. '/' +function input.generators.tex(specification) + local instance = input.instance + local tag = specification + if not instance.lsrmode and lfs.dir then + input.report("scanning path %s",specification) + instance.files[tag] = { } + local files = instance.files[tag] + local n, m, r = 0, 0, 0 + local spec = specification .. '/' + local attributes = lfs.attributes + local directory = lfs.dir + local small = instance.smallcache + local function action(path) + local mode, full + if path then + full = spec .. path .. '/' + else + full = spec + end + for name in directory(full) do + if name:find("^%.") then + -- skip + -- elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%<%>%,%?\n\r\t]") then -- too much escaped + elseif weird:match(name) then + -- texio.write_nl("skipping " .. name) + -- skip else - full = spec - end - for name in directory(full) do - if name:find("^%.") then - -- skip - -- elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%<%>%,%?\n\r\t]") then -- too much escaped - elseif weird:match(name) then - -- texio.write_nl("skipping " .. name) - -- skip - else - mode = attributes(full..name,'mode') - if mode == "directory" then - m = m + 1 - if path then - action(path..'/'..name) - else - action(name) - end - elseif path and mode == 'file' then - n = n + 1 - local f = files[name] - if f then - if not small then - if type(f) == 'string' then - files[name] = { f, path } - else - f[#f+1] = path - end - end - else - files[name] = path - local lower = name:lower() - if name ~= lower then - files["remap:"..lower] = name - r = r + 1 - end - end + mode = attributes(full..name,'mode') + if mode == 'directory' then + m = m + 1 + if path then + action(path..'/'..name) + else + action(name) end - end - end - end - action() - 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 = '.' - local f = io.open(fullname) - if f then - instance.files[tag] = { } - local files = instance.files[tag] - local small = instance.smallcache - input.report("loading lsr file",fullname) - -- for line in f:lines() do -- much slower then the next one - for line in (f:read("*a")):gmatch("(.-)\n") do - if line:find("^[%a%d]") then - local fl = files[line] - if fl then + elseif path and mode == 'file' then + n = n + 1 + local f = files[name] + if f then if not small then - if type(fl) == 'string' then - files[line] = { fl, path } -- table + if type(f) == 'string' then + files[name] = { f, path } else - fl[#fl+1] = path + f[#f+1] = path end end else - files[line] = path -- string - local lower = line:lower() - if line ~= lower then - files["remap:"..lower] = line + files[name] = path + local lower = name:lower() + if name ~= lower then + files["remap:"..lower] = name + r = r + 1 + end + end + end + end + end + end + action() + input.report("%s files found on %s directories with %s uppercase remappings",n,m,r) + else + local fullname = file.join(specification,input.lsrname) + local path = '.' + local f = io.open(fullname) + if f then + instance.files[tag] = { } + local files = instance.files[tag] + local small = instance.smallcache + input.report("loading lsr file %s",fullname) + -- for line in f:lines() do -- much slower then the next one + for line in (f:read("*a")):gmatch("(.-)\n") do + if line:find("^[%a%d]") then + local fl = files[line] + if fl then + if not small then + if type(fl) == 'string' then + files[line] = { fl, path } -- table + else + fl[#fl+1] = path end end else - path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line + files[line] = path -- string + local lower = line:lower() + if line ~= lower then + files["remap:"..lower] = line + end end + else + path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line end - f:close() end + f:close() end end - end -- savers, todo -function input.savefiles(instance) - input.aux.save_data(instance, 'files', function(k,v) - return instance.validfile(k,v) -- path, name +function input.savefiles() + input.aux.save_data('files', function(k,v) + return input.instance.validfile(k,v) -- path, name end) end @@ -5527,8 +5841,8 @@ end -- we join them and split them after the expansion has taken place. This -- is more convenient. -function input.splitconfig(instance) - for i,c in ipairs(instance) do +function input.splitconfig() + for i,c in ipairs(input.instance) do for k,v in pairs(c) do if type(v) == 'string' then local t = file.split_path(v) @@ -5539,8 +5853,9 @@ function input.splitconfig(instance) end end end -function input.joinconfig(instance) - for i,c in ipairs(instance.order) do + +function input.joinconfig() + for i,c in ipairs(input.instance.order) do for k,v in pairs(c) do if type(v) == 'table' then c[k] = file.join_path(v) @@ -5563,8 +5878,9 @@ function input.join_path(str) end end -function input.splitexpansions(instance) - for k,v in pairs(instance.expansions) do +function input.splitexpansions() + local ie = input.instance.expansions + for k,v in pairs(ie) do local t, h = { }, { } for _,vv in pairs(file.split_path(v)) do if vv ~= "" and not h[vv] then @@ -5573,19 +5889,19 @@ function input.splitexpansions(instance) end end if #t > 1 then - instance.expansions[k] = t + ie[k] = t else - instance.expansions[k] = t[1] + ie[k] = t[1] end end end -- end of split/join code -function input.saveoldconfig(instance) - input.splitconfig(instance) - input.aux.save_data(instance, 'configuration', nil) - input.joinconfig(instance) +function input.saveoldconfig() + input.splitconfig() + input.aux.save_data('configuration', nil) + input.joinconfig() end input.configbanner = [[ @@ -5614,7 +5930,7 @@ function input.serialize(files) end end t[#t+1] = "return {" - if instance.sortdata then + if input.instance.sortdata then for _, k in pairs(sorted(files)) do local fk = files[k] if type(fk) == 'table' then @@ -5646,11 +5962,11 @@ 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 +function input.aux.save_data(dataname, check, makename) -- untested without cache overload + for cachename, files in pairs(input.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) + local luaname, lucname = name .. ".lua", name .. ".luc" + input.report("preparing %s for %s",dataname,cachename) 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 @@ -5668,38 +5984,38 @@ function input.aux.save_data(instance, dataname, check, makename) -- untested wi 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 - input.report("compiling failed for " .. dataname .. ", deleting file " .. lucname) + local ok = io.savedata(luaname,input.serialize(data)) + if ok then + input.report("%s saved in %s",dataname,luaname) + if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip + input.report("%s compiled to %s",dataname,lucname) + else + input.report("compiling failed for %s, deleting file %s",dataname,lucname) os.remove(lucname) end else - input.report("unable to save " .. dataname .. " in " .. name..input.luasuffix) + input.report("unable to save %s in %s (access error)",dataname,luaname) end end end -function input.aux.load_data(instance,pathname,dataname,filename,makename) -- untested without cache overload +function input.aux.load_data(pathname,dataname,filename,makename) -- untested without cache overload + local instance = input.instance 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) + local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua") 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) + input.report("loading %s for %s from %s",dataname,pathname,filename) instance[dataname][pathname] = data.content else - input.report("skipping",dataname,"for",pathname,"from",filename) + input.report("skipping %s for %s from %s",dataname,pathname,filename) instance[dataname][pathname] = { } instance.loaderror = true end else - input.report("skipping",dataname,"for",pathname,"from",filename) + input.report("skipping %s for %s from %s",dataname,pathname,filename) end end @@ -5712,13 +6028,14 @@ end -- TEXMFBOGUS = 'effe checken of dit werkt', -- } -function input.aux.load_texmfcnf(instance,dataname,pathname) +function input.aux.load_texmfcnf(dataname,pathname) + local instance = input.instance local filename = file.join(pathname,input.luaname) local blob = loadfile(filename) if blob then local data = blob() if data then - input.report("loading","configuration file",filename) + input.report("loading configuration file %s",filename) if true then -- flatten to variable.progname local t = { } @@ -5738,169 +6055,168 @@ function input.aux.load_texmfcnf(instance,dataname,pathname) instance[dataname][pathname] = data end else - input.report("skipping","configuration file",filename) + input.report("skipping configuration file %s",filename) instance[dataname][pathname] = { } instance.loaderror = true end else - input.report("skipping","configuration file",filename) + input.report("skipping configuration file %s",filename) end end -function input.aux.load_configuration(instance,dname,lname) - input.aux.load_data(instance,dname,'configuration',lname and file.basename(lname)) +function input.aux.load_configuration(dname,lname) + input.aux.load_data(dname,'configuration',lname and file.basename(lname)) end -function input.aux.load_files(instance,tag) - input.aux.load_data(instance,tag,'files') +function input.aux.load_files(tag) + input.aux.load_data(tag,'files') end -function input.resetconfig(instance) +function input.resetconfig() + input.identify_own() + local instance = input.instance instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false end -function input.loadnewconfig(instance) +function input.loadnewconfig() + local instance = input.instance for _, cnf in ipairs(instance.luafiles) do local dname = file.dirname(cnf) - input.aux.load_texmfcnf(instance,'setup',dname) + input.aux.load_texmfcnf('setup',dname) instance.order[#instance.order+1] = instance.setup[dname] if instance.loaderror then break end end end -function input.loadoldconfig(instance) +function input.loadoldconfig() + local instance = input.instance if not instance.renewcache then for _, cnf in ipairs(instance.cnffiles) do local dname = file.dirname(cnf) - input.aux.load_configuration(instance,dname) + input.aux.load_configuration(dname) instance.order[#instance.order+1] = instance.configuration[dname] if instance.loaderror then break end end end - input.joinconfig(instance) + input.joinconfig() end -function input.expand_variables(instance) - instance.expansions = { } ---~ 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 +function input.expand_variables() + local instance = input.instance + local expansions, environment, variables = { }, instance.environment, instance.variables + local env = input.env + instance.expansions = expansions + if instance.engine ~= "" then environment['engine'] = instance.engine end + if instance.progname ~= "" then environment['progname'] = instance.progname end + for k,v in pairs(environment) do local a, b = k:match("^(%a+)%_(.*)%s*$") if a and b then - instance.expansions[a..'.'..b] = v + expansions[a..'.'..b] = v else - instance.expansions[k] = v + expansions[k] = v end end - for k,v in pairs(instance.environment) do -- move environment to expansions - if not instance.expansions[k] then instance.expansions[k] = v end + for k,v in pairs(environment) do -- move environment to expansions + if not expansions[k] then expansions[k] = v end end - for k,v in pairs(instance.variables) do -- move variables to expansions - if not instance.expansions[k] then instance.expansions[k] = v end + for k,v in pairs(variables) do -- move variables to expansions + if not expansions[k] then expansions[k] = v end end while true do local busy = false - for k,v in pairs(instance.expansions) do + for k,v in pairs(expansions) do local s, n = v:gsub("%$([%a%d%_%-]+)", function(a) busy = true - return instance.expansions[a] or input.env(instance,a) + return expansions[a] or env(a) end) local s, m = s:gsub("%$%{([%a%d%_%-]+)%}", function(a) busy = true - return instance.expansions[a] or input.env(instance,a) + return expansions[a] or env(a) end) if n > 0 or m > 0 then - instance.expansions[k]= s + expansions[k]= s end end if not busy then break end end - for k,v in pairs(instance.expansions) do - instance.expansions[k] = v:gsub("\\", '/') + for k,v in pairs(expansions) do + expansions[k] = v:gsub("\\", '/') end end -function input.aux.expand_vars(instance,lst) -- simple vars +function input.aux.expand_vars(lst) -- simple vars + local instance = input.instance + local variables, env = instance.variables, input.env for k,v in pairs(lst) do lst[k] = v:gsub("%$([%a%d%_%-]+)", function(a) - return instance.variables[a] or input.env(instance,a) + return variables[a] or env(a) end) end end -function input.aux.expanded_var(instance,var) -- simple vars +function input.aux.expanded_var(var) -- simple vars + local instance = input.instance return var:gsub("%$([%a%d%_%-]+)", function(a) - return instance.variables[a] or input.env(instance,a) + return instance.variables[a] or input.env(a) end) end -function input.aux.entry(instance,entries,name) +function input.aux.entry(entries,name) if name and (name ~= "") then + local instance = input.instance name = name:gsub('%$','') local result = entries[name..'.'..instance.progname] or entries[name] if result then return result else - result = input.env(instance,name) + result = input.env(name) if result then instance.variables[name] = result - input.expand_variables(instance) + input.expand_variables() return instance.expansions[name] or "" end end end return "" end -function input.variable(instance,name) - return input.aux.entry(instance,instance.variables,name) +function input.variable(name) + return input.aux.entry(input.instance.variables,name) end -function input.expansion(instance,name) - return input.aux.entry(instance,instance.expansions,name) +function input.expansion(name) + return input.aux.entry(input.instance.expansions,name) end -function input.aux.is_entry(instance,entries,name) +function input.aux.is_entry(entries,name) if name and name ~= "" then name = name:gsub('%$','') - return (entries[name..'.'..instance.progname] or entries[name]) ~= nil + return (entries[name..'.'..input.instance.progname] or entries[name]) ~= nil else return false end end -function input.is_variable(instance,name) - return input.aux.is_entry(instance,instance.variables,name) -end -function input.is_expansion(instance,name) - return input.aux.is_entry(instance,instance.expansions,name) +function input.is_variable(name) + return input.aux.is_entry(input.instance.variables,name) end -function input.simplified_list(str) - if type(str) == 'table' then - return str -- troubles ; ipv , in texmf - elseif str == '' then - return { } - else - local t = { } - for _,v in ipairs(string.splitchr(str:gsub("^\{(.+)\}$","%1"),",")) do - t[#t+1] = (v:gsub("^[%!]*(.+)[%/\\]*$","%1")) - end - return t - end +function input.is_expansion(name) + return input.aux.is_entry(input.instance.expansions,name) end -function input.unexpanded_path_list(instance,str) - local pth = input.variable(instance,str) +function input.unexpanded_path_list(str) + local pth = input.variable(str) local lst = input.split_path(pth) - return input.aux.expanded_path(instance,lst) + return input.aux.expanded_path(lst) end -function input.unexpanded_path(instance,str) - return file.join_path(input.unexpanded_path_list(instance,str)) + +function input.unexpanded_path(str) + return file.join_path(input.unexpanded_path_list(str)) end do local done = { } - function input.reset_extra_path(instance) + function input.reset_extra_path() + local instance = input.instance local ep = instance.extra_paths if not ep then ep, done = { }, { } @@ -5910,7 +6226,8 @@ do end end - function input.register_extra_path(instance,paths,subpaths) + function input.register_extra_path(paths,subpaths) + local instance = input.instance local ep = instance.extra_paths or { } local n = #ep if paths and paths ~= "" then @@ -5955,7 +6272,8 @@ do end -function input.expanded_path_list(instance,str) +function input.expanded_path_list(str) + local instance = input.instance local function made_list(list) local ep = instance.extra_paths if not ep or #ep == 0 then @@ -5996,39 +6314,41 @@ function input.expanded_path_list(instance,str) -- engine+progname hash str = str:gsub("%$","") if not instance.lists[str] then -- cached - local lst = made_list(input.split_path(input.expansion(instance,str))) - instance.lists[str] = input.aux.expanded_path(instance,lst) + local lst = made_list(input.split_path(input.expansion(str))) + instance.lists[str] = input.aux.expanded_path(lst) end return instance.lists[str] else - local lst = input.split_path(input.expansion(instance,str)) - return made_list(input.aux.expanded_path(instance,lst)) + local lst = input.split_path(input.expansion(str)) + return made_list(input.aux.expanded_path(lst)) end end -function input.expand_path(instance,str) - return file.join_path(input.expanded_path_list(instance,str)) + +function input.clean_path_list(str) + local t = input.expanded_path_list(str) + if t then + for i=1,#t do + t[i] = file.collapse_path(input.clean_path(t[i])) + end + end + return t end ---~ function input.first_writable_path(instance,name) ---~ for _,v in pairs(input.expanded_path_list(instance,name)) do ---~ if file.is_writable(file.join(v,'luatex-cache.tmp')) then ---~ return v ---~ end ---~ end ---~ return "." ---~ end +function input.expand_path(str) + return file.join_path(input.expanded_path_list(str)) +end -function input.expanded_path_list_from_var(instance,str) -- brrr +function input.expanded_path_list_from_var(str) -- brrr local tmp = input.var_of_format_or_suffix(str:gsub("%$","")) if tmp ~= "" then - return input.expanded_path_list(instance,str) + return input.expanded_path_list(str) else - return input.expanded_path_list(instance,tmp) + return input.expanded_path_list(tmp) end end -function input.expand_path_from_var(instance,str) - return file.join_path(input.expanded_path_list_from_var(instance,str)) +function input.expand_path_from_var(str) + return file.join_path(input.expanded_path_list_from_var(str)) end function input.format_of_var(str) @@ -6058,9 +6378,9 @@ function input.var_of_format_or_suffix(str) return '' end -function input.expand_braces(instance,str) -- output variable and brace expansion of STRING - local ori = input.variable(instance,str) - local pth = input.aux.expanded_path(instance,input.split_path(ori)) +function input.expand_braces(str) -- output variable and brace expansion of STRING + local ori = input.variable(str) + local pth = input.aux.expanded_path(input.split_path(ori)) return file.join_path(pth) end @@ -6075,6 +6395,7 @@ end -- {a,b,c/{p,q,r}/d/{x,y,z}//} -- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}} -- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}} +-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c} -- this one is better and faster, but it took me a while to realize -- that this kind of replacement is cleaner than messy parsing and @@ -6083,19 +6404,20 @@ end -- work that well; the parsing is ok, but dealing with the resulting -- table is a pain because we need to work inside-out recursively --- get rid of piecewise here, just a gmatch is ok - function input.aux.splitpathexpr(str, t, validate) -- no need for optimization, only called a few times, we can use lpeg for the sub t = t or { } local concat = table.concat + str = str:gsub(",}",",@}") + str = str:gsub("{,","{@,") + -- str = "@" .. str .. "@" while true do local done = false while true do local ok = false - str = str:gsub("([^{},]+){([^{}]-)}", function(a,b) + str = str:gsub("([^{},]+){([^{}]+)}", function(a,b) local t = { } - b:piecewise(",", function(s) t[#t+1] = a .. s end) + for s in b:gmatch("[^,]+") do t[#t+1] = a .. s end ok, done = true, true return "{" .. concat(t,",") .. "}" end) @@ -6103,9 +6425,9 @@ function input.aux.splitpathexpr(str, t, validate) end while true do local ok = false - str = str:gsub("{([^{}]-)}([^{},]+)", function(a,b) + str = str:gsub("{([^{}]+)}([^{},]+)", function(a,b) local t = { } - a:piecewise(",", function(s) t[#t+1] = s .. b end) + for s in a:gmatch("[^,]+") do t[#t+1] = s .. b end ok, done = true, true return "{" .. concat(t,",") .. "}" end) @@ -6113,50 +6435,41 @@ function input.aux.splitpathexpr(str, t, validate) end while true do local ok = false - str = str:gsub("([,{]){([^{}]+)}([,}])", function(a,b,c) + str = str:gsub("{([^{}]+)}{([^{}]+)}", function(a,b) + local t = { } + for sa in a:gmatch("[^,]+") do + for sb in b:gmatch("[^,]+") do + t[#t+1] = sa .. sb + end + end ok, done = true, true - return a .. b .. c + return "{" .. concat(t,",") .. "}" end) if not ok then break end end - if not done then break end - end - while true do - local ok = false - str = str:gsub("{([^{}]-)}{([^{}]-)}", function(a,b) - local t = { } - a:piecewise(",", function(sa) - b:piecewise(",", function(sb) - t[#t+1] = sa .. sb - end) - end) - ok = true - return "{" .. concat(t,",") .. "}" - end) - if not ok then break end - end - while true do - local ok = false - str = str:gsub("{([^{}]-)}", function(a) - ok = true - return a + str = str:gsub("({[^{}]*){([^{}]+)}([^{}]*})", function(a,b,c) + done = true + return a .. b.. c end) - if not ok then break end + if not done then break end end + str = str:gsub("[{}]", "") + str = str:gsub("@","") if validate then - str:piecewise(",", function(s) + for s in str:gmatch("[^,]+") do s = validate(s) if s then t[#t+1] = s end - end) + end else - str:piecewise(",", function(s) + for s in str:gmatch("[^,]+") do t[#t+1] = s - end) + end end return t end -function input.aux.expanded_path(instance,pathlist) -- maybe not a list, just a path +function input.aux.expanded_path(pathlist) -- maybe not a list, just a path + local instance = input.instance -- a previous version fed back into pathlist local newlist, ok = { }, false for _,v in ipairs(pathlist) do @@ -6188,17 +6501,16 @@ input.is_readable = { } function input.aux.is_readable(readable, name) if input.trace > 2 then if readable then - input.logger("+ readable", name) + input.logger("+ readable: %s",name) else - input.logger("- readable", name) + input.logger("- readable: %s", name) end end return readable end function input.is_readable.file(name) - -- return input.aux.is_readable(file.is_readable(name), name) - return input.aux.is_readable(input.aux.is_file(name), name) + return input.aux.is_readable(lfs.isfile(name), name) end input.is_readable.tex = input.is_readable.file @@ -6206,12 +6518,13 @@ input.is_readable.tex = input.is_readable.file -- name -- name/name -function input.aux.collect_files(instance,names) +function input.aux.collect_files(names) + local instance = input.instance local filelist = { } for _, fname in pairs(names) do if fname then if input.trace > 2 then - input.logger("? blobpath asked",fname) + input.logger("? blobpath asked: %s",fname) end local bname = file.basename(fname) local dname = file.dirname(fname) @@ -6225,7 +6538,7 @@ function input.aux.collect_files(instance,names) local files = blobpath and instance.files[blobpath] if files then if input.trace > 2 then - input.logger('? blobpath do',blobpath .. " (" .. bname ..")") + input.logger('? blobpath do: %s (%s)',blobpath,bname) end local blobfile = files[bname] if not blobfile then @@ -6258,7 +6571,7 @@ function input.aux.collect_files(instance,names) end end elseif input.trace > 1 then - input.logger('! blobpath no',blobpath .. " (" .. bname ..")" ) + input.logger('! blobpath no: %s (%s)',blobpath,bname) end end end @@ -6313,15 +6626,17 @@ do end -function input.aux.register_in_trees(instance,name) +function input.aux.register_in_trees(name) if not name:find("^%.") then + local instance = input.instance instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one end end -- split the next one up, better for jit -function input.aux.find_file(instance,filename) -- todo : plugin (scanners, checkers etc) +function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc) + local instance = input.instance local result = { } local stamp = nil filename = input.normalize_name(filename) -- elsewhere @@ -6330,16 +6645,22 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format if instance.found[stamp] then - input.logger('! remembered', filename) + if input.trace > 0 then + input.logger('! remembered: %s',filename) + end return instance.found[stamp] end end if filename:find('%*') then - input.logger('! wildcard', filename) - result = input.find_wildcard_files(instance,filename) + if input.trace > 0 then + input.logger('! wildcard: %s', filename) + end + result = input.find_wildcard_files(filename) elseif input.aux.qualified_path(filename) then if input.is_readable.file(filename) then - input.logger('! qualified', filename) + if input.trace > 0 then + input.logger('! qualified: %s', filename) + end result = { filename } else local forcedname, ok = "", false @@ -6347,22 +6668,26 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec if instance.format == "" then forcedname = filename .. ".tex" if input.is_readable.file(forcedname) then - input.logger('! no suffix, forcing standard filetype tex') + if input.trace > 0 then + input.logger('! no suffix, forcing standard filetype: tex') + end result, ok = { forcedname }, true end else for _, s in pairs(input.suffixes_of_format(instance.format)) do forcedname = filename .. "." .. s if input.is_readable.file(forcedname) then - input.logger('! no suffix, forcing format filetype', s) + if input.trace > 0 then + input.logger('! no suffix, forcing format filetype: %s', s) + end result, ok = { forcedname }, true break end end end end - if not ok then - input.logger('? qualified', filename) + if not ok and input.trace > 0 then + input.logger('? qualified: %s', filename) end end else @@ -6380,10 +6705,14 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec local forcedname = filename .. '.tex' wantedfiles[#wantedfiles+1] = forcedname filetype = input.format_of_suffix(forcedname) - input.logger('! forcing filetype',filetype) + if input.trace > 0 then + input.logger('! forcing filetype: %s',filetype) + end else filetype = input.format_of_suffix(filename) - input.logger('! using suffix based filetype',filetype) + if input.trace > 0 then + input.logger('! using suffix based filetype: %s',filetype) + end end else if ext == "" then @@ -6392,16 +6721,18 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec end end filetype = instance.format - input.logger('! using given filetype',filetype) + if input.trace > 0 then + input.logger('! using given filetype: %s',filetype) + end end local typespec = input.variable_of_format(filetype) - local pathlist = input.expanded_path_list(instance,typespec) + local pathlist = input.expanded_path_list(typespec) if not pathlist or #pathlist == 0 then -- no pathlist, access check only / todo == wildcard if input.trace > 2 then - input.logger('? filename',filename) - input.logger('? filetype',filetype or '?') - input.logger('? wanted files',table.concat(wantedfiles," | ")) + input.logger('? filename: %s',filename) + input.logger('? filetype: %s',filetype or '?') + input.logger('? wanted files: %s',table.concat(wantedfiles," | ")) end for _, fname in pairs(wantedfiles) do if fname and input.is_readable.file(fname) then @@ -6411,7 +6742,7 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec end end -- this is actually 'other text files' or 'any' or 'whatever' - local filelist = input.aux.collect_files(instance,wantedfiles) + local filelist = input.aux.collect_files(wantedfiles) local fl = filelist and filelist[1] if fl then filename = fl[3] @@ -6420,12 +6751,12 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec end else -- list search - local filelist = input.aux.collect_files(instance,wantedfiles) + local filelist = input.aux.collect_files(wantedfiles) local doscan, recurse if input.trace > 2 then - input.logger('? filename',filename) - -- if pathlist then input.logger('? path list',table.concat(pathlist," | ")) end - -- if filelist then input.logger('? file list',table.concat(filelist," | ")) end + input.logger('? filename: %s',filename) + -- if pathlist then input.logger('? path list: %s',table.concat(pathlist," | ")) end + -- if filelist then input.logger('? file list: %s',table.concat(filelist," | ")) end end -- a bit messy ... esp the doscan setting here for _, path in pairs(pathlist) do @@ -6446,11 +6777,11 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec if f:find(expr) then -- input.debug('T',' '..f) if input.trace > 2 then - input.logger('= found in hash',f) + input.logger('= found in hash: %s',f) end --- todo, test for readable result[#result+1] = fl[3] - input.aux.register_in_trees(instance,f) -- for tracing used files + input.aux.register_in_trees(f) -- for tracing used files done = true if not instance.allresults then break end else @@ -6464,12 +6795,12 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec local pname = pathname:gsub("%.%*$",'') if not pname:find("%*") then local ppname = pname:gsub("/+$","") - if input.aux.can_be_dir(instance,ppname) then + if input.aux.can_be_dir(ppname) then for _, w in pairs(wantedfiles) do local fname = file.join(ppname,w) if input.is_readable.file(fname) then if input.trace > 2 then - input.logger('= found by scanning',fname) + input.logger('= found by scanning: %s',fname) end result[#result+1] = fname done = true @@ -6498,40 +6829,29 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec return result end -input.aux._find_file_ = input.aux.find_file +input.aux._find_file_ = input.aux.find_file -- frozen variant -function input.aux.find_file(instance,filename) -- maybe make a lowres cache too - local result = input.aux._find_file_(instance,filename) +function input.aux.find_file(filename) -- maybe make a lowres cache too + local result = input.aux._find_file_(filename) if #result == 0 then local lowered = filename:lower() if filename ~= lowered then - return input.aux._find_file_(instance,lowered) + return input.aux._find_file_(lowered) end end return result end -if lfs and lfs.isfile then - input.aux.is_file = lfs.isfile -- to be done: use this -else - input.aux.is_file = file.is_readable -end - -if lfs and lfs.isdir then - function input.aux.can_be_dir(instance,name) - if not instance.fakepaths[name] then - if lfs.isdir(name) then - instance.fakepaths[name] = 1 -- directory - else - instance.fakepaths[name] = 2 -- no directory - end +function input.aux.can_be_dir(name) + local instance = input.instance + if not instance.fakepaths[name] then + if lfs.isdir(name) then + instance.fakepaths[name] = 1 -- directory + else + instance.fakepaths[name] = 2 -- no directory end - return (instance.fakepaths[name] == 1) - end -else - function input.aux.can_be_dir() - return true end + return (instance.fakepaths[name] == 1) end if not input.concatinators then input.concatinators = { } end @@ -6539,7 +6859,8 @@ if not input.concatinators then input.concatinators = { } end input.concatinators.tex = file.join input.concatinators.file = input.concatinators.tex -function input.find_files(instance,filename,filetype,mustexist) +function input.find_files(filename,filetype,mustexist) + local instance = input.instance if type(mustexist) == boolean then -- all set elseif type(filetype) == 'boolean' then @@ -6548,16 +6869,17 @@ function input.find_files(instance,filename,filetype,mustexist) filetype, mustexist = nil, false end instance.format = filetype or '' - local t = input.aux.find_file(instance,filename,true) + local t = input.aux.find_file(filename,true) instance.format = '' return t end -function input.find_file(instance,filename,filetype,mustexist) - return (input.find_files(instance,filename,filetype,mustexist)[1] or "") +function input.find_file(filename,filetype,mustexist) + return (input.find_files(filename,filetype,mustexist)[1] or "") end -function input.find_given_files(instance,filename) +function input.find_given_files(filename) + local instance = input.instance local bname, result = file.basename(filename), { } for k, hash in ipairs(instance.hashes) do local files = instance.files[hash.tag] @@ -6585,11 +6907,12 @@ function input.find_given_files(instance,filename) return result end -function input.find_given_file(instance,filename) - return (input.find_given_files(instance,filename)[1] or "") +function input.find_given_file(filename) + return (input.find_given_files(filename)[1] or "") end -function input.find_wildcard_files(instance,filename) -- todo: remap: +function input.find_wildcard_files(filename) -- todo: remap: + local instance = input.instance local result = { } local bname, dname = file.basename(filename), file.dirname(filename) local path = dname:gsub("^*/","") @@ -6645,13 +6968,14 @@ function input.find_wildcard_files(instance,filename) -- todo: remap: return result end -function input.find_wildcard_file(instance,filename) - return (input.find_wildcard_files(instance,filename)[1] or "") +function input.find_wildcard_file(filename) + return (input.find_wildcard_files(filename)[1] or "") end -- main user functions -function input.save_used_files_in_trees(instance, filename,jobname) +function input.save_used_files_in_trees(filename,jobname) + local instance = input.instance if not filename then filename = 'luatex.jlg' end local f = io.open(filename,'w') if f then @@ -6670,24 +6994,24 @@ function input.save_used_files_in_trees(instance, filename,jobname) end end -function input.automount(instance) +function input.automount() -- implemented later 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) - input.automount(instance) - input.stoptiming(instance) +function input.load() + input.starttiming(input.instance) + input.resetconfig() + input.identify_cnf() + input.load_lua() + input.expand_variables() + input.load_cnf() + input.expand_variables() + input.load_hash() + input.automount() + input.stoptiming(input.instance) end -function input.for_files(instance, command, files, filetype, mustexist) +function input.for_files(command, files, filetype, mustexist) if files and #files > 0 then local function report(str) if input.verbose then @@ -6700,7 +7024,7 @@ function input.for_files(instance, command, files, filetype, mustexist) report('') end for _, file in pairs(files) do - local result = command(instance,file,filetype,mustexist) + local result = command(file,filetype,mustexist) if type(result) == 'string' then report(result) else @@ -6714,14 +7038,11 @@ end -- strtab -function input.var_value(instance,str) -- output the value of variable $STRING. - return input.variable(instance,str) -end -function input.expand_var(instance,str) -- output variable expansion of STRING. - return input.expansion(instance,str) -end -function input.show_path(instance,str) -- output search path for file type NAME - return file.join_path(input.expanded_path_list(instance,input.format_of_var(str))) +input.var_value = input.variable -- output the value of variable $STRING. +input.expand_var = input.expansion -- output variable expansion of STRING. + +function input.show_path(str) -- output search path for file type NAME + return file.join_path(input.expanded_path_list(input.format_of_var(str))) end -- input.find_file(filename) @@ -6773,53 +7094,55 @@ function table.sequenced(t,sep) -- temp here return table.concat(s, sep or " | ") end -function input.methodhandler(what, instance, filename, filetype) -- ... +function input.methodhandler(what, filename, filetype) -- ... local specification = (type(filename) == "string" and input.splitmethod(filename)) or filename -- no or { }, let it bomb local scheme = specification.scheme if input[what][scheme] then - input.logger('= handler',specification.original .." -> " .. what .. " -> " .. table.sequenced(specification)) - return input[what][scheme](instance,filename,filetype) -- todo: specification + if input.trace > 0 then + input.logger('= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification)) + end + return input[what][scheme](filename,filetype) -- todo: specification else - return input[what].tex(instance,filename,filetype) -- todo: specification + return input[what].tex(filename,filetype) -- todo: specification end end -- also inside next test? -function input.findtexfile(instance, filename, filetype) - return input.methodhandler('finders',instance, input.normalize_name(filename), filetype) +function input.findtexfile(filename, filetype) + return input.methodhandler('finders',input.normalize_name(filename), filetype) end -function input.opentexfile(instance,filename) - return input.methodhandler('openers',instance, input.normalize_name(filename)) +function input.opentexfile(filename) + return input.methodhandler('openers',input.normalize_name(filename)) end -function input.findbinfile(instance, filename, filetype) - return input.methodhandler('finders',instance, input.normalize_name(filename), filetype) +function input.findbinfile(filename, filetype) + return input.methodhandler('finders',input.normalize_name(filename), filetype) end -function input.openbinfile(instance,filename) - return input.methodhandler('loaders',instance, input.normalize_name(filename)) +function input.openbinfile(filename) + return input.methodhandler('loaders',input.normalize_name(filename)) end -function input.loadbinfile(instance, filename, filetype) - local fname = input.findbinfile(instance, input.normalize_name(filename), filetype) +function input.loadbinfile(filename, filetype) + local fname = input.findbinfile(input.normalize_name(filename), filetype) if fname and fname ~= "" then - return input.openbinfile(instance,fname) + return input.openbinfile(fname) else return unpack(input.loaders.notfound) end end -function input.texdatablob(instance, filename, filetype) - local ok, data, size = input.loadbinfile(instance, filename, filetype) +function input.texdatablob(filename, filetype) + local ok, data, size = input.loadbinfile(filename, filetype) return data or "" end input.loadtexfile = input.texdatablob -function input.openfile(filename) -- brrr texmf.instance here / todo ! ! ! ! ! - local fullname = input.findtexfile(texmf.instance, filename) +function input.openfile(filename) + local fullname = input.findtexfile(filename) if fullname and (fullname ~= "") then - return input.opentexfile(texmf.instance, fullname) + return input.opentexfile(fullname) else return nil end @@ -6865,16 +7188,18 @@ end -- beware: i need to check where we still need a / on windows: function input.clean_path(str) ---~ return (((str:gsub("\\","/")):gsub("^!+","")):gsub("//+","//")) if str then - return ((str:gsub("\\","/")):gsub("^!+","")) + str = str:gsub("\\","/") + str = str:gsub("^!+","") + str = str:gsub("^~",input.homedir) + return str else return nil end end function input.do_with_path(name,func) - for _, v in pairs(input.expanded_path_list(instance,name)) do + for _, v in pairs(input.expanded_path_list(name)) do func("^"..input.clean_path(v)) end end @@ -6883,7 +7208,8 @@ function input.do_with_var(name,func) func(input.aux.expanded_var(name)) end -function input.with_files(instance,pattern,handle) +function input.with_files(pattern,handle) + local instance = input.instance for _, hash in ipairs(instance.hashes) do local blobpath = hash.tag local blobtype = hash.type @@ -6910,37 +7236,22 @@ function input.with_files(instance,pattern,handle) end end ---~ function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix ---~ newname = file.addsuffix(newname,"lua") ---~ local newscript = input.clean_path(input.find_file(instance, newname)) ---~ local oldscript = input.clean_path(oldname) ---~ input.report("old script", oldscript) ---~ input.report("new script", newscript) ---~ if oldscript ~= newscript and (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then ---~ local newdata = io.loaddata(newscript) ---~ if newdata then ---~ input.report("old script content replaced by new content") ---~ io.savedata(oldscript,newdata) ---~ end ---~ end ---~ end - -function input.update_script(instance,oldname,newname) -- oldname -> own.name, not per se a suffix +function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix local scriptpath = "scripts/context/lua" newname = file.addsuffix(newname,"lua") local oldscript = input.clean_path(oldname) - input.report("to be replaced old script", oldscript) - local newscripts = input.find_files(instance, newname) or { } + input.report("to be replaced old script %s", oldscript) + local newscripts = input.find_files(newname) or { } if #newscripts == 0 then input.report("unable to locate new script") else for _, newscript in ipairs(newscripts) do newscript = input.clean_path(newscript) - input.report("checking new script", newscript) + input.report("checking new script %s", newscript) if oldscript == newscript then input.report("old and new script are the same") elseif not newscript:find(scriptpath) then - input.report("new script should come from",scriptpath) + input.report("new script should come from %s",scriptpath) elseif not (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then input.report("invalid new script name") else @@ -6968,10 +7279,10 @@ do local resolvers = { } - resolvers.environment = function(instance,str) + resolvers.environment = function(str) return input.clean_path(os.getenv(str) or os.getenv(str:upper()) or os.getenv(str:lower()) or "") end - resolvers.relative = function(instance,str,n) + resolvers.relative = function(str,n) if io.exists(str) then -- nothing elseif io.exists("./" .. str) then @@ -6989,16 +7300,16 @@ do end return input.clean_path(str) end - resolvers.locate = function(instance,str) - local fullname = input.find_given_file(instance,str) or "" + resolvers.locate = function(str) + local fullname = input.find_given_file(str) or "" return input.clean_path((fullname ~= "" and fullname) or str) end - resolvers.filename = function(instance,str) - local fullname = input.find_given_file(instance,str) or "" + resolvers.filename = function(str) + local fullname = input.find_given_file(str) or "" return input.clean_path(file.basename((fullname ~= "" and fullname) or str)) end - resolvers.pathname = function(instance,str) - local fullname = input.find_given_file(instance,str) or "" + resolvers.pathname = function(str) + local fullname = input.find_given_file(str) or "" return input.clean_path(file.dirname((fullname ~= "" and fullname) or str)) end @@ -7010,15 +7321,15 @@ do resolvers.file = resolvers.filename resolvers.path = resolvers.pathname - local function resolve(instance,str) + local function resolve(str) if type(str) == "table" then for k, v in pairs(str) do - str[k] = resolve(instance,v) or v + str[k] = resolve(v) or v end elseif str and str ~= "" then - str = str:gsub("([a-z]+):([^ ]+)", function(method,target) + str = str:gsub("([a-z]+):([^ ]*)", function(method,target) if resolvers[method] then - return resolvers[method](instance,target) + return resolvers[method](target) else return method .. ":" .. target end @@ -7027,10 +7338,173 @@ do return str end + if os.uname then + for k, v in pairs(os.uname()) do + if not resolvers[k] then + resolvers[k] = function() return v end + end + end + end + input.resolve = resolve end +function input.boolean_variable(str,default) + local b = input.expansion("PURGECACHE") + if b == "" then + return default + else + b = toboolean(b) + return (b == nil and default) or b + end +end + + +if not modules then modules = { } end modules ['luat-log'] = { + version = 1.001, + comment = "companion to luat-lib.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +--[[ldx-- +<p>This is a prelude to a more extensive logging module. For the sake +of parsing log files, in addition to the standard logging we will +provide an <l n='xml'/> structured file. Actually, any logging that +is hooked into callbacks will be \XML\ by default.</p> +--ldx]]-- + +-- input.logger -> special tracing, driven by log level (only input) +-- input.report -> goes to terminal, depends on verbose, has banner +-- logs.report -> module specific tracing and reporting, no banner but class + + +input = input or { } +logs = logs or { } + +--[[ldx-- +<p>This looks pretty ugly but we need to speed things up a bit.</p> +--ldx]]-- + +logs.levels = { + ['error'] = 1, + ['warning'] = 2, + ['info'] = 3, + ['debug'] = 4 +} + +logs.functions = { + 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct' +} + +logs.callbacks = { + 'start_page_number', + 'stop_page_number', + 'report_output_pages', + 'report_output_log' +} + +logs.tracers = { +} + +logs.xml = logs.xml or { } +logs.tex = logs.tex or { } + +logs.level = 0 + +local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format + +if texlua then + write_nl = print + write = io.write +end + +function logs.xml.report(category,fmt,...) -- new + write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...))) +end +function logs.xml.line(fmt,...) -- new + write_nl(format("<r>%s</r>",format(fmt,...))) +end + +function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end +function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end +function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end +function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end + +function logs.tex.report(category,fmt,...) -- new + -- write_nl(format("%s | %s",category,format(fmt,...))) -- arg to format can be tex comment so .. . + write_nl(category .. " | " .. format(fmt,...)) +end +function logs.tex.line(fmt,...) -- new + write_nl(format(fmt,...)) +end + +function logs.set_level(level) + logs.level = logs.levels[level] or level +end + +function logs.set_method(method) + for _, v in pairs(logs.functions) do + logs[v] = logs[method][v] or function() end + end + if callback and input[method] then + for _, cb in pairs(logs.callbacks) do + callback.register(cb, input[method][cb]) + end + end +end + +function logs.xml.start_page_number() + write_nl(format("<p real='%s' page='%s' sub='%s'", tex.count[0], tex.count[1], tex.count[2])) +end + +function logs.xml.stop_page_number() + write("/>") + write_nl("") +end + +function logs.xml.report_output_pages(p,b) + write_nl(format("<v k='pages' v='%s'/>", p)) + write_nl(format("<v k='bytes' v='%s'/>", b)) + write_nl("") +end + +function logs.xml.report_output_log() +end + +function input.logger(...) -- assumes test for input.trace > n + if input.trace > 0 then + logs.report(...) + end +end + +function input.report(fmt,...) + if input.verbose then + logs.report(input.banner or "report",format(fmt,...)) + end +end + +function input.reportlines(str) -- todo: <lines></lines> + for line in str:gmatch("(.-)[\n\r]") do + logs.report(input.banner or "report",line) + end +end + +function input.help(banner,message) + if not input.verbose then + input.verbose = true + -- input.report(banner,"\n") + end + input.report(banner,"\n") + input.report("") + input.reportlines(message) +end + +logs.set_level('error') +logs.set_method('tex') + if not modules then modules = { } end modules ['luat-tmp'] = { version = 1.001, @@ -7056,63 +7530,82 @@ being written at the same time is small. We also need to extend luatools with a recache feature.</p> --ldx]]-- +local format = string.format + caches = caches or { } dir = dir or { } texmf = texmf or { } -caches.path = caches.path or nil -caches.base = caches.base or "luatex-cache" -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.paths = caches.paths or nil -caches.force = false - -input.usecache = not toboolean(os.getenv("TEXMFSHARECACHE") or "false",true) -- true - -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 +caches.path = caches.path or nil +caches.base = caches.base or "luatex-cache" +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.paths = caches.paths or nil +caches.force = false +caches.defaults = { "TEXMFCACHE", "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" } + +function caches.temp() + local cachepath = nil + local function check(list,isenv) + if not cachepath then + for _, v in ipairs(list) do + cachepath = (isenv and (os.env[v] or "")) or v or "" + if cachepath == "" then + -- next + else + cachepath = input.clean_path(cachepath) + if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory" + break + elseif caches.force or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then + dir.mkdirs(cachepath) + if lfs.isdir(cachepath) and file.iswritable(cachepath) then + break + end + end + end + cachepath = nil + end end end - local cachepath = input.expanded_path_list(instance,"TEXMFCACHE") - cachepath = cachepath and #cachepath > 0 and checkpath(cachepath[1]) + check(input.clean_path_list("TEXMFCACHE") or { }) + check(caches.defaults,true) 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") + print("\nfatal error: there is no valid (writable) 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)) + elseif not lfs.isdir(cachepath) then -- lfs.attributes(cachepath,"mode") ~= "directory" + print(format("\nfatal error: cache path %s is not a directory\n",cachepath)) os.exit() end - function caches.temp(instance) + cachepath = input.normalize_name(cachepath) + function caches.temp() return cachepath end return cachepath end -function caches.configpath(instance) - return table.concat(instance.cnffiles,";") +function caches.configpath() + return table.concat(input.instance.cnffiles,";") end function caches.hashed(tree) return md5.hex((tree:lower()):gsub("[\\\/]+","/")) end -function caches.treehash(instance) - local tree = caches.configpath(instance) +--~ tracing: + +--~ function caches.hashed(tree) +--~ tree = (tree:lower()):gsub("[\\\/]+","/") +--~ local hash = md5.hex(tree) +--~ if input.verbose then -- temp message +--~ input.report("hashing %s => %s",tree,hash) +--~ end +--~ return hash +--~ end + +function caches.treehash() + local tree = caches.configpath() if not tree or tree == "" then return false else @@ -7120,14 +7613,14 @@ function caches.treehash(instance) end end -function caches.setpath(instance,...) +function caches.setpath(...) if not caches.path then if not caches.path then - caches.path = caches.temp(instance) + caches.path = caches.temp() end caches.path = input.clean_path(caches.path) -- to be sure if lfs then - caches.tree = caches.tree or caches.treehash(instance) + caches.tree = caches.tree or caches.treehash() if caches.tree then caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree) else @@ -7147,9 +7640,9 @@ function caches.setpath(instance,...) return caches.path end -function caches.definepath(instance,category,subcategory) +function caches.definepath(category,subcategory) return function() - return caches.setpath(instance,category,subcategory) + return caches.setpath(category,subcategory) end end @@ -7172,26 +7665,38 @@ function caches.is_writable(filepath,filename) return file.is_writable(tmaname) end -function caches.savedata(filepath,filename,data,raw) -- raw needed for file cache +function input.boolean_variable(str,default) + local b = input.expansion("PURGECACHE") + if b == "" then + return default + else + b = toboolean(b) + return (b == nil and default) or b + end +end + +function caches.savedata(filepath,filename,data,raw) local tmaname, tmcname = caches.setluanames(filepath,filename) local reduce, simplify = true, true if raw then reduce, simplify = false, false end if caches.direct then - file.savedata(tmaname, table.serialize(data,'return',true,true)) + file.savedata(tmaname, table.serialize(data,'return',true,true,false)) -- no hex else - table.tofile (tmaname, data,'return',true,true) -- maybe not the last true + table.tofile(tmaname, data,'return',true,true,false) -- maybe not the last true end - utils.lua.compile(tmaname, tmcname) + local cleanup = input.boolean_variable("PURGECACHE", false) + local strip = input.boolean_variable("LUACSTRIP", true) + utils.lua.compile(tmaname, tmcname, cleanup, strip) end -- here we use the cache for format loading (texconfig.[formatname|jobname]) --~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then -if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and texmf.instance then +if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and input.instance then if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc - texconfig.formatname = caches.setpath(texmf.instance,"formats") .. "/" .. texconfig.luaname:gsub("%.lu.$",".fmt") + texconfig.formatname = caches.setpath("formats") .. "/" .. texconfig.luaname:gsub("%.lu.$",".fmt") end --[[ldx-- @@ -7214,7 +7719,7 @@ do -- local report local function report(container,tag,name) if caches.trace or containers.trace or container.trace then - logs.report(string.format("%s cache",container.subcategory),string.format("%s: %s",tag,name or 'invalid')) + logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid') end end @@ -7239,7 +7744,7 @@ do -- local report enabled = enabled, version = version or 1.000, trace = false, - path = caches.setpath(texmf.instance,category,subcategory), + path = caches.setpath(category,subcategory), } c[subcategory] = s end @@ -7304,13 +7809,16 @@ end -- reimplement the saver. local save_data = input.aux.save_data +local load_data = input.aux.load_data -input.cachepath = nil +input.cachepath = nil -- public, for tracing +input.usecache = true -- public, for tracing -function input.aux.save_data(instance, dataname, check) - input.cachepath = input.cachepath or caches.definepath(instance,"trees") - save_data(instance, dataname, check, function(cachename,dataname) +function input.aux.save_data(dataname, check) + save_data(dataname, check, function(cachename,dataname) + input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true) if input.usecache then + input.cachepath = input.cachepath or caches.definepath("trees") return file.join(input.cachepath(),caches.hashed(cachename)) else return file.join(cachename,dataname) @@ -7318,12 +7826,11 @@ function input.aux.save_data(instance, dataname, check) end) end -local load_data = input.aux.load_data - -function input.aux.load_data(instance,pathname,dataname,filename) - input.cachepath = input.cachepath or caches.definepath(instance,"trees") - load_data(instance,pathname,dataname,filename,function(dataname,filename) +function input.aux.load_data(pathname,dataname,filename) + load_data(pathname,dataname,filename,function(dataname,filename) + input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true) if input.usecache then + input.cachepath = input.cachepath or caches.definepath("trees") return file.join(input.cachepath(),caches.hashed(pathname)) else if not filename or (filename == "") then @@ -7338,13 +7845,13 @@ end input.automounted = input.automounted or { } -function input.automount(instance,usecache) - local mountpaths = input.simplified_list(input.expansion(instance,'TEXMFMOUNT')) +function input.automount(usecache) + local mountpaths = input.clean_path_list(input.expansion('TEXMFMOUNT')) if table.is_empty(mountpaths) and usecache then - mountpaths = { caches.setpath(instance,"mount") } + mountpaths = { caches.setpath("mount") } end if not table.is_empty(mountpaths) then - input.starttiming(instance) + input.starttiming(input.instance) for k, root in pairs(mountpaths) do local f = io.open(root.."/url.tmi") if f then @@ -7353,16 +7860,16 @@ function input.automount(instance,usecache) if line:find("^[%%#%-]") then -- or %W -- skip elseif line:find("^zip://") then - input.report("mounting",line) + input.report("mounting %s",line) table.insert(input.automounted,line) - input.usezipfile(instance,line) + input.usezipfile(line) end end end f:close() end end - input.stoptiming(instance) + input.stoptiming(input.instance) end end @@ -7411,17 +7918,17 @@ function input.storage.dump() else name = str end - initialize = string.format("%s %s = %s or {} ", initialize, name, name) + initialize = format("%s %s = %s or {} ", initialize, name, name) end if evaluate then finalize = "input.storage.evaluate(" .. name .. ")" end input.storage.max = input.storage.max + 1 if input.storage.trace then - logs.report('storage',string.format('saving %s in slot %s',message,input.storage.max)) + logs.report('storage','saving %s in slot %s',message,input.storage.max) code = initialize .. - string.format("logs.report('storage','restoring %s from slot %s') ",message,input.storage.max) .. + format("logs.report('storage','restoring %s from slot %s') ",message,input.storage.max) .. table.serialize(original,name) .. finalize else @@ -7457,6 +7964,11 @@ provide an <l n='xml'/> structured file. Actually, any logging that is hooked into callbacks will be \XML\ by default.</p> --ldx]]-- +-- input.logger -> special tracing, driven by log level (only input) +-- input.report -> goes to terminal, depends on verbose, has banner +-- logs.report -> module specific tracing and reporting, no banner but class + + input = input or { } logs = logs or { } @@ -7472,8 +7984,7 @@ logs.levels = { } logs.functions = { - 'error', 'warning', 'info', 'debug', 'report', - 'start', 'stop', 'push', 'pop' + 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct' } logs.callbacks = { @@ -7483,89 +7994,100 @@ logs.callbacks = { 'report_output_log' } +logs.tracers = { +} + logs.xml = logs.xml or { } logs.tex = logs.tex or { } logs.level = 0 -do - local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format +local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format - if texlua then - write_nl = print - write = io.write - end +if texlua then + write_nl = print + write = io.write +end - function logs.xml.debug(category,str) - if logs.level > 3 then write_nl(format("<d category='%s'>%s</d>",category,str)) end - end - function logs.xml.info(category,str) - if logs.level > 2 then write_nl(format("<i category='%s'>%s</i>",category,str)) end - end - function logs.xml.warning(category,str) - if logs.level > 1 then write_nl(format("<w category='%s'>%s</w>",category,str)) end - end - function logs.xml.error(category,str) - if logs.level > 0 then write_nl(format("<e category='%s'>%s</e>",category,str)) end - end - function logs.xml.report(category,str) - write_nl(format("<r category='%s'>%s</r>",category,str)) - end +function logs.xml.report(category,fmt,...) -- new + write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...))) +end +function logs.xml.line(fmt,...) -- new + write_nl(format("<r>%s</r>",format(fmt,...))) +end - function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end - function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end - function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end - function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end +function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end +function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end +function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end +function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end - function logs.tex.debug(category,str) - if logs.level > 3 then write_nl(format("debug >> %s: %s" ,category,str)) end - end - function logs.tex.info(category,str) - if logs.level > 2 then write_nl(format("info >> %s: %s" ,category,str)) end - end - function logs.tex.warning(category,str) - if logs.level > 1 then write_nl(format("warning >> %s: %s",category,str)) end - end - function logs.tex.error(category,str) - if logs.level > 0 then write_nl(format("error >> %s: %s" ,category,str)) end - end - function logs.tex.report(category,str) - write_nl(format("report >> %s: %s" ,category,str)) - end +function logs.tex.report(category,fmt,...) -- new + -- write_nl(format("%s | %s",category,format(fmt,...))) -- arg to format can be tex comment so .. . + write_nl(category .. " | " .. format(fmt,...)) +end +function logs.tex.line(fmt,...) -- new + write_nl(format(fmt,...)) +end - function logs.set_level(level) - logs.level = logs.levels[level] or level - end +function logs.set_level(level) + logs.level = logs.levels[level] or level +end - function logs.set_method(method) - for _, v in pairs(logs.functions) do - logs[v] = logs[method][v] or function() end - end - if callback and input[method] then - for _, cb in pairs(logs.callbacks) do - callback.register(cb, input[method][cb]) - end +function logs.set_method(method) + for _, v in pairs(logs.functions) do + logs[v] = logs[method][v] or function() end + end + if callback and input[method] then + for _, cb in pairs(logs.callbacks) do + callback.register(cb, input[method][cb]) end end +end - function logs.xml.start_page_number() - write_nl(format("<p real='%s' page='%s' sub='%s'", tex.count[0], tex.count[1], tex.count[2])) - end +function logs.xml.start_page_number() + write_nl(format("<p real='%s' page='%s' sub='%s'", tex.count[0], tex.count[1], tex.count[2])) +end + +function logs.xml.stop_page_number() + write("/>") + write_nl("") +end + +function logs.xml.report_output_pages(p,b) + write_nl(format("<v k='pages' v='%s'/>", p)) + write_nl(format("<v k='bytes' v='%s'/>", b)) + write_nl("") +end + +function logs.xml.report_output_log() +end - function logs.xml.stop_page_number() - write("/>") - write_nl("") +function input.logger(...) -- assumes test for input.trace > n + if input.trace > 0 then + logs.report(...) end +end - function logs.xml.report_output_pages(p,b) - write_nl(format("<v k='pages' v='%s'/>", p)) - write_nl(format("<v k='bytes' v='%s'/>", b)) - write_nl("") +function input.report(fmt,...) + if input.verbose then + logs.report(input.banner or "report",format(fmt,...)) end +end - function logs.xml.report_output_log() +function input.reportlines(str) -- todo: <lines></lines> + for line in str:gmatch("(.-)[\n\r]") do + logs.report(input.banner or "report",line) end +end +function input.help(banner,message) + if not input.verbose then + input.verbose = true + -- input.report(banner,"\n") + end + input.report(banner,"\n") + input.report("") + input.reportlines(message) end logs.set_level('error') @@ -7758,7 +8280,7 @@ end -- end library merge -own = { } +own = { } -- not local own.libs = { -- todo: check which ones are really needed 'l-string.lua', @@ -7778,6 +8300,7 @@ own.libs = { -- todo: check which ones are really needed -- 'l-tex.lua', 'luat-lib.lua', 'luat-inp.lua', + 'luat-log.lua', -- 'luat-zip.lua', -- 'luat-tex.lua', -- 'luat-kps.lua', @@ -7807,7 +8330,7 @@ table.insert(own.list,own.path.."/../../../tex/context/base") table.insert(own.list,own.path.."/mtx") table.insert(own.list,own.path.."/../sources") -function locate_libs() +local function locate_libs() for _, lib in pairs(own.libs) do for _, pth in pairs(own.list) do local filename = string.gsub(pth .. "/" .. lib,"\\","/") @@ -7834,38 +8357,19 @@ if not input then os.exit() end -instance = input.reset() +input.instance = input.reset() input.verbose = environment.argument("verbose") or false -input.banner = 'MtxRun | ' +input.banner = 'MtxRun' utils.report = input.report +local instance = input.instance + instance.engine = environment.argument("engine") or 'luatex' instance.progname = environment.argument("progname") or 'context' instance.lsrmode = environment.argument("lsr") or false -- use os.env or environment when available ---~ function input.check_environment(tree) ---~ input.report('') ---~ os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME')) ---~ if os.platform == 'linux' then ---~ os.setenv('TEXOS', os.getenv('TEXOS') or 'texmf-linux') ---~ elseif os.platform == 'windows' then ---~ os.setenv('TEXOS', os.getenv('TEXOS') or 'texmf-windows') ---~ elseif os.platform == 'macosx' then ---~ os.setenv('TEXOS', os.getenv('TEXOS') or 'texmf-macosx') ---~ end ---~ os.setenv('TEXOS', string.gsub(string.gsub(os.getenv('TEXOS'),"^[\\\/]*", ''),"[\\\/]*$", '')) ---~ os.setenv('TEXPATH', string.gsub(tree,"\/+$",'')) ---~ os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS')) ---~ input.report('') ---~ input.report("preset : TEXPATH => " .. os.getenv('TEXPATH')) ---~ input.report("preset : TEXOS => " .. os.getenv('TEXOS')) ---~ input.report("preset : TEXMFOS => " .. os.getenv('TEXMFOS')) ---~ input.report("preset : TMP => " .. os.getenv('TMP')) ---~ input.report('') ---~ end - function input.check_environment(tree) input.report('') os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME')) @@ -7873,10 +8377,10 @@ function input.check_environment(tree) os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",'')) os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS')) input.report('') - input.report("preset : TEXPATH => " .. os.getenv('TEXPATH')) - input.report("preset : TEXOS => " .. os.getenv('TEXOS')) - input.report("preset : TEXMFOS => " .. os.getenv('TEXMFOS')) - input.report("preset : TMP => " .. os.getenv('TMP')) + input.report("preset : TEXPATH => %s", os.getenv('TEXPATH')) + input.report("preset : TEXOS => %s", os.getenv('TEXOS')) + input.report("preset : TEXMFOS => %s", os.getenv('TEXMFOS')) + input.report("preset : TMP => %s", os.getenv('TMP')) input.report('') end @@ -7965,9 +8469,9 @@ function file.needs_updating(oldname,newname) -- size modification access change end end -function file.mdchecksum(name) +function file.checksum(name) if md5 then - local data = io.loadall(name) + local data = io.loaddata(name) if data then return md5.HEXsum(data) end @@ -7976,24 +8480,18 @@ function file.mdchecksum(name) end function file.loadchecksum(name) - if md then - local data = io.loadall(name .. ".md5") - if data then - return string.gsub(md5.HEXsum(data),"%s$","") - end + if md5 then + local data = io.loaddata(name .. ".md5") + return data and data:gsub("%s","") end return nil end function file.savechecksum(name, checksum) - if not checksum then checksum = file.mdchecksum(name) end + if not checksum then checksum = file.checksum(name) end if checksum then - local f = io.open(name .. ".md5","w") - if f then - f:write(checksum) - f:close() - return checksum - end + io.savedata(name .. ".md5",checksum) + return checksum end return nil end @@ -8097,46 +8595,46 @@ messages.help = [[ --progname=str format or backend --edit launch editor with found file ---launch (--all) launch files (assume os support) +--launch (--all) launch files like manuals, assumes os support --intern run script using built in libraries ]] -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) +function input.runners.my_prepare_a() + input.resetconfig() + input.identify_cnf() + input.load_lua() + input.expand_variables() + input.load_cnf() + input.expand_variables() end -function input.runners.my_prepare_b(instance) - input.runners.my_prepare_a(instance) - input.load_hash(instance) - input.automount(instance) +function input.runners.my_prepare_b() + input.runners.my_prepare_a() + input.load_hash() + input.automount() end -function input.runners.prepare(instance) +function input.runners.prepare() local checkname = environment.argument("ifchanged") if checkname and checkname ~= "" then local oldchecksum = file.loadchecksum(checkname) local newchecksum = file.checksum(checkname) if oldchecksum == newchecksum then - report("file '" .. checkname .. "' is unchanged") + input.report("file '%s' is unchanged",checkname) return "skip" else - report("file '" .. checkname .. "' is changed, processing started") + input.report("file '%s' is changed, processing started",checkname) end file.savechecksum(checkname) end local oldname, newname = string.split(environment.argument("iftouched") or "", ",") if oldname and newname and oldname ~= "" and newname ~= "" then if not file.needs_updating(oldname,newname) then - report("file '" .. oldname .. "' and '" .. newname .. "'have same age") + input.report("file '%s' and '%s' have same age",oldname,newname) return "skip" else - report("file '" .. newname .. "' is older than '" .. oldname .. "'") + input.report("file '%s' is older than '%s'",oldname,newname) end end local tree = environment.argument('tree') or "" @@ -8155,15 +8653,16 @@ function input.runners.prepare(instance) end local runpath = environment.argument("path") if runpath and not dir.chdir(runpath) then - input.report("unable to change to path '" .. runpath .. "'") + input.report("unable to change to path '%s'",runpath) return "error" end return "run" end -function input.runners.execute_script(instance,fullname,internal) +function input.runners.execute_script(fullname,internal) + local instance = input.instance if fullname and fullname ~= "" then - local state = input.runners.prepare(instance) + local state = input.runners.prepare() if state == 'error' then return false elseif state == 'skip' then @@ -8187,16 +8686,16 @@ function input.runners.execute_script(instance,fullname,internal) if suffix == "" then -- loop over known suffixes for _,s in pairs(input.runners.suffixes) do - result = input.find_file(instance, name .. "." .. s, 'texmfscripts') + result = input.find_file(name .. "." .. s, 'texmfscripts') if result ~= "" then break end end elseif input.runners.applications[suffix] then - result = input.find_file(instance, name, 'texmfscripts') + result = input.find_file(name, 'texmfscripts') else -- maybe look on path - result = input.find_file(instance, name, 'other text files') + result = input.find_file(name, 'other text files') end end if result and result ~= "" then @@ -8212,7 +8711,7 @@ function input.runners.execute_script(instance,fullname,internal) local before, after = environment.split_arguments(fullname) local command = result .. " " .. environment.reconstruct_commandline(after) input.report("") - input.report("executing: " .. command) + input.report("executing: %s",command) input.report("\n \n") io.flush() local code = os.exec(command) -- maybe spawn @@ -8224,9 +8723,9 @@ function input.runners.execute_script(instance,fullname,internal) return false end -function input.runners.execute_program(instance,fullname) +function input.runners.execute_program(fullname) if fullname and fullname ~= "" then - local state = input.runners.prepare(instance) + local state = input.runners.prepare() if state == 'error' then return false elseif state == 'skip' then @@ -8237,7 +8736,7 @@ function input.runners.execute_program(instance,fullname) fullname = fullname:gsub("^bin:","") local command = fullname .. " " .. environment.reconstruct_commandline(after) input.report("") - input.report("executing: " .. command) + input.report("executing: %s",command) input.report("\n \n") io.flush() local code = os.exec(command) -- (fullname,unpack(after)) does not work / maybe spawn @@ -8247,12 +8746,12 @@ function input.runners.execute_program(instance,fullname) return false end -function input.runners.handle_stubs(instance,create) +function input.runners.handle_stubs(create) local stubpath = environment.argument('stubpath') or '.' -- 'auto' no longer supported local windows = environment.argument('windows') or environment.argument('mswin') or false local unix = environment.argument('unix') or environment.argument('linux') or false if not windows and not unix then - if environment.platform == "unix" then + if os.platform == "unix" then unix = true else windows = true @@ -8267,41 +8766,41 @@ function input.runners.handle_stubs(instance,create) local command = "luatex --luaonly mtxrun.lua " .. name if windows then io.savedata(base..".bat", {"@echo off", command.." %*"}, "\013\010") - input.report("windows stub for '" .. base .. "' created") + input.report("windows stub for '%s' created",base) end if unix then io.savedata(base, {"#!/bin/sh", command..' "$@"'}, "\010") - input.report("unix stub for '" .. base .. "' created") + input.report("unix stub for '%s' created",base) end else if windows and (os.remove(base..'.bat') or os.remove(base..'.cmd')) then - input.report("windows stub for '" .. base .. "' removed") + input.report("windows stub for '%s' removed", base) end if unix and (os.remove(base) or os.remove(base..'.sh')) then - input.report("unix stub for '" .. base .. "' removed") + input.report("unix stub for '%s' removed",base) end end end end end -function input.runners.resolve_string(instance,filename) +function input.runners.resolve_string(filename) if filename and filename ~= "" then - input.runners.report_location(instance,input.resolve(instance,filename)) + input.runners.report_location(input.resolve(filename)) end end -function input.runners.locate_file(instance,filename) +function input.runners.locate_file(filename) if filename and filename ~= "" then - input.runners.report_location(instance,input.find_given_file(instance,filename)) + input.runners.report_location(input.find_given_file(filename)) end end -function input.runners.locate_platform(instance) - input.runners.report_location(instance,os.currentplatform()) +function input.runners.locate_platform() + input.runners.report_location(os.currentplatform()) end -function input.runners.report_location(instance,result) +function input.runners.report_location(result) if input.verbose then input.report("") if result and result ~= "" then @@ -8314,9 +8813,9 @@ function input.runners.report_location(instance,result) end end -function input.runners.edit_script(instance,filename) +function input.runners.edit_script(filename) local editor = os.getenv("MTXRUN_EDITOR") or os.getenv("TEXMFSTART_EDITOR") or os.getenv("EDITOR") or 'scite' - local rest = input.resolve(instance,filename) + local rest = input.resolve(filename) if rest ~= "" then os.launch(editor .. " " .. rest) end @@ -8361,7 +8860,8 @@ function input.launch(str) os.launch(str) end -function input.runners.launch_file(instance,filename) +function input.runners.launch_file(filename) + local instance = input.instance instance.allresults = true input.verbose = true local pattern = environment.arguments["pattern"] @@ -8371,25 +8871,30 @@ function input.runners.launch_file(instance,filename) if not pattern or pattern == "" then input.report("provide name or --pattern=") else - local t = input.find_files(instance,pattern) - -- local t = input.aux.find_file(instance,"*/" .. pattern,true) + local t = input.find_files(pattern) + if not t or #t == 0 then + t = input.aux.find_file("*/" .. pattern,true) + end + if not t or #t == 0 then + t = input.aux.find_file("*/" .. pattern .. "*",true) + end if t and #t > 0 then if environment.arguments["all"] then for _, v in pairs(t) do - input.report("launching", v) + input.report("launching %s", v) input.launch(v) end else - input.report("launching", t[1]) + input.report("launching %s", t[1]) input.launch(t[1]) end else - input.report("no match for", pattern) + input.report("no match for %s", pattern) end end end -function input.runners.execute_ctx_script(instance,filename,arguments) +function input.runners.execute_ctx_script(filename,arguments) local function found(name) local path = file.dirname(name) if path and path ~= "" then @@ -8404,25 +8909,25 @@ function input.runners.execute_ctx_script(instance,filename,arguments) local fullname = filename -- just <filename> fullname = filename .. suffix - fullname = input.find_file(instance,fullname) + fullname = input.find_file(fullname) -- mtx-<filename> if not fullname or fullname == "" then fullname = "mtx-" .. filename .. suffix - fullname = found(fullname) or input.find_file(instance,fullname) + fullname = found(fullname) or input.find_file(fullname) end -- mtx-<filename>s if not fullname or fullname == "" then fullname = "mtx-" .. filename .. "s" .. suffix - fullname = found(fullname) or input.find_file(instance,fullname) + fullname = found(fullname) or input.find_file(fullname) end -- mtx-<filename minus trailing s> if not fullname or fullname == "" then fullname = "mtx-" .. filename:gsub("s$","") .. suffix - fullname = found(fullname) or input.find_file(instance,fullname) + fullname = found(fullname) or input.find_file(fullname) end -- that should do it if fullname and fullname ~= "" then - local state = input.runners.prepare(instance) + local state = input.runners.prepare() if state == 'error' then return false elseif state == 'skip' then @@ -8439,7 +8944,7 @@ function input.runners.execute_ctx_script(instance,filename,arguments) end filename = environment.files[1] if input.verbose then - input.report("using script: " .. fullname) + input.report("using script: %s\n",fullname) end dofile(fullname) local savename = environment.arguments['save'] @@ -8452,20 +8957,16 @@ function input.runners.execute_ctx_script(instance,filename,arguments) end else input.verbose = true - input.report("unknown script: " .. filename) + if filename == "" then + input.report("unknown script") + else + input.report("unknown script: %s",filename) + end return false end end -input.report(banner,"\n") - -function input.help(banner,message) - if not input.verbose then - input.verbose = true - input.report(banner,"\n") - end - input.reportlines(message) -end +input.report("%s\n",banner) -- this is a bit dirty ... first we store the first filename and next we -- split the arguments so that we only see the ones meant for this script @@ -8476,9 +8977,9 @@ local ok = true local before, after = environment.split_arguments(filename) -input.runners.my_prepare_b(instance) -before = input.resolve(instance,before) -- experimental here -after = input.resolve(instance,after) -- experimental here +input.runners.my_prepare_b() +before = input.resolve(before) -- experimental here +after = input.resolve(after) -- experimental here environment.initialize_arguments(before) @@ -8490,60 +8991,53 @@ elseif environment.argument("selfclean") then utils.merger.selfclean(own.name) elseif environment.argument("selfupdate") then input.verbose = true - input.update_script(instance,own.name,"mtxrun") + input.update_script(own.name,"mtxrun") elseif environment.argument("ctxlua") or environment.argument("internal") then -- run a script by loading it (using libs) - ok = input.runners.execute_script(instance,filename,true) + ok = input.runners.execute_script(filename,true) elseif environment.argument("script") then -- run a script by loading it (using libs), pass args - ok = input.runners.execute_ctx_script(instance,filename,after) + ok = input.runners.execute_ctx_script(filename,after) elseif environment.argument("execute") then -- execute script - ok = input.runners.execute_script(instance,filename) + ok = input.runners.execute_script(filename) elseif environment.argument("direct") then -- equals bin: - ok = input.runners.execute_program(instance,filename) + ok = input.runners.execute_program(filename) elseif environment.argument("edit") then -- edit file - input.runners.edit_script(instance,filename) + input.runners.edit_script(filename) elseif environment.argument("launch") then - input.runners.launch_file(instance,filename) + input.runners.launch_file(filename) elseif environment.argument("make") then -- make stubs - input.runners.handle_stubs(instance,true) + input.runners.handle_stubs(true) elseif environment.argument("remove") then -- remove stub - input.runners.handle_stubs(instance,false) + input.runners.handle_stubs(false) elseif environment.argument("resolve") then -- resolve string - input.runners.resolve_string(instance,filename) + input.runners.resolve_string(filename) elseif environment.argument("locate") then -- locate file - input.runners.locate_file(instance,filename) + input.runners.locate_file(filename) elseif environment.argument("platform")then -- locate platform - input.runners.locate_platform(instance) + input.runners.locate_platform() elseif environment.argument("help") or filename=='help' or filename == "" then input.help(banner,messages.help) -- execute script if filename:find("^bin:") then - ok = input.runners.execute_program(instance,filename) + ok = input.runners.execute_program(filename) else - ok = input.runners.execute_script(instance,filename) + ok = input.runners.execute_script(filename) end end ---~ if input.verbose then ---~ input.report("") ---~ input.report(string.format("runtime: %0.3f seconds",os.runtime())) ---~ end - ---~ if ok then ---~ input.report("exit code: 0") os.exit(0) ---~ else ---~ input.report("exit code: 1") os.exit(1) ---~ end - -if environment.platform == "unix" then +if os.platform == "unix" then io.write("\n") end + +if ok == false then ok = 1 elseif ok == true then ok = 0 end + +os.exit(ok) diff --git a/scripts/context/lua/x-ldx.lua b/scripts/context/lua/x-ldx.lua index d9d4e6a72..67d5f925c 100644 --- a/scripts/context/lua/x-ldx.lua +++ b/scripts/context/lua/x-ldx.lua @@ -150,38 +150,38 @@ function ldx.enhance(data) -- i need to use lpeg and then we can properly autoin cod = cod:gsub("(%a+)",function(key) local class = ldx.keywords.reserved[key] if class then - return "<ldx:key class='" .. class .. "'>" .. key .. "</ldx:key>" + return "<key class='" .. class .. "'>" .. key .. "</key>" else return key end end) cod = cod:gsub("<<<<(%d+)>>>>", function(s) - return "<ldx:dqs>" .. dqs[tonumber(s)] .. "</ldx:dqs>" + return "<dqs>" .. dqs[tonumber(s)] .. "</dqs>" end) cod = cod:gsub("<<(%d+)>>", function(s) - return "<ldx:sqs>" .. sqs[tonumber(s)] .. "</ldx:sqs>" + return "<sqs>" .. sqs[tonumber(s)] .. "</sqs>" end) cod = cod:gsub("%[%[%[%[(%d+)%]%]%]%]", function(s) return cmt[tonumber(s)] end) cod = cod:gsub("%[%[(%d+)%]%]", function(s) - return "<ldx:com>" .. com[tonumber(s)] .. "</ldx:com>" + return "<com>" .. com[tonumber(s)] .. "</com>" end) cod = cod:gsub("##d##", "\\\"") cod = cod:gsub("##s##", "\\\'") if ldx.make_index then local lines = cod:split("\n") - local f = "(<ldx:key class='1'>function</ldx:key>)%s+([%w%.]+)%s*%(" + local f = "(<key class='1'>function</key>)%s+([%w%.]+)%s*%(" for k,v in pairs(lines) do -- functies v = v:gsub(f,function(key, str) - return "<ldx:function>" .. str .. "</ldx:function>(" + return "<function>" .. str .. "</function>(" end) -- variables v = v:gsub("^([%w][%w%,%s]-)(=[^=])",function(str, rest) local t = string.split(str, ",%s*") for k,v in pairs(t) do - t[k] = "<ldx:variable>" .. v .. "</ldx:variable>" + t[k] = "<variable>" .. v .. "</variable>" end return table.join(t,", ") .. rest end) @@ -222,19 +222,19 @@ function ldx.enhance(data) -- i need to use lpeg and then we can properly autoin cod = cod:gsub("(%a+)",function(key) local class = ldx.keywords.reserved[key] if class then - return "<ldx:key class='" .. class .. "'>" .. key .. "</ldx:key>" + return "<key class='" .. class .. "'>" .. key .. "</key>" else return key end end) cod = cod:gsub("<s<<<(%d+)>>>s>", function(s) - return "<ldx:sqs>" .. sqs[tonumber(s)] .. "</ldx:sqs>" + return "<sqs>" .. sqs[tonumber(s)] .. "</sqs>" end) cod = cod:gsub("<d<<<(%d+)>>>d>", function(s) - return "<ldx:dqs>" .. dqs[tonumber(s)] .. "</ldx:dqs>" + return "<dqs>" .. dqs[tonumber(s)] .. "</dqs>" end) cod = cod:gsub("<c<<<(%d+)>>>c>", function(s) - return "<ldx:com>" .. com[tonumber(s)] .. "</ldx:com>" + return "<com>" .. com[tonumber(s)] .. "</com>" end) cod = cod:gsub("<l<<<(%d+)>>>l>", function(s) return cmt[tonumber(s)] @@ -243,17 +243,17 @@ function ldx.enhance(data) -- i need to use lpeg and then we can properly autoin cod = cod:gsub("##s##", "\\\'") if ldx.make_index then local lines = cod:split("\n") - local f = "(<ldx:key class='1'>function</ldx:key>)%s+([%w%.]+)%s*%(" + local f = "(<key class='1'>function</key>)%s+([%w%.]+)%s*%(" for k,v in pairs(lines) do -- functies v = v:gsub(f,function(key, str) - return "<ldx:function>" .. str .. "</ldx:function>(" + return "<function>" .. str .. "</function>(" end) -- variables v = v:gsub("^([%w][%w%,%s]-)(=[^=])",function(str, rest) local t = string.split(str, ",%s*") for k,v in pairs(t) do - t[k] = "<ldx:variable>" .. v .. "</ldx:variable>" + t[k] = "<variable>" .. v .. "</variable>" end return table.join(t,", ") .. rest end) @@ -279,44 +279,46 @@ it possible to change the indentation afterwards. function ldx.as_xml(data) local t, cmode = { }, false t[#t+1] = "<?xml version='1.0' standalone='yes'?>\n" - t[#t+1] = "\n<ldx:document xmlns:ldx='http://www.pragma-ade.com/schemas/ldx.rng'>\n" - for _,v in pairs(data) do + t[#t+1] = "\n<document xmlns:ldx='http://www.pragma-ade.com/schemas/ldx.rng' xmlns='http://www.pragma-ade.com/schemas/ldx.rng'>\n" + for _,v in pairs(data) do -- ldx: not needed if v.code and not v.code:is_empty() then - t[#t+1] = "\n<ldx:code>\n" + t[#t+1] = "\n<code>\n" for k,v in pairs(v.code:split("\n")) do -- make this faster local a, b = v:find("^(%s+)") + if v then v = v:gsub("[\n\r ]+$","") end if a and b then + v = v:sub(b+1,#v) if cmode then - t[#t+1] = "<ldx:line comment='yes' n='" .. b .. "'>" .. v:sub(b+1,#v) .. "</ldx:line>\n" + t[#t+1] = "<line comment='yes' n='" .. b .. "'>" .. v .. "</line>\n" else - t[#t+1] = "<ldx:line n='" .. b .. "'>" .. v:sub(b+1,#v) .. "</ldx:line>\n" + t[#t+1] = "<line n='" .. b .. "'>" .. v .. "</line>\n" end elseif v:is_empty() then if cmode then - t[#t+1] = "<ldx:line comment='yes'/>\n" + t[#t+1] = "<line comment='yes'/>\n" else - t[#t+1] = "<ldx:line/>\n" + t[#t+1] = "<line/>\n" end elseif v:find("^%-%-%[%[") then - t[#t+1] = "<ldx:line comment='yes'>" .. v .. "</ldx:line>\n" + t[#t+1] = "<line comment='yes'>" .. v .. "</line>\n" cmode= true elseif v:find("^%]%]%-%-") then - t[#t+1] = "<ldx:line comment='yes'>" .. v .. "</ldx:line>\n" + t[#t+1] = "<line comment='yes'>" .. v .. "</line>\n" cmode= false elseif cmode then - t[#t+1] = "<ldx:line comment='yes'>" .. v .. "</ldx:line>\n" + t[#t+1] = "<line comment='yes'>" .. v .. "</line>\n" else - t[#t+1] = "<ldx:line>" .. v .. "</ldx:line>\n" + t[#t+1] = "<line>" .. v .. "</line>\n" end end - t[#t+1] = "</ldx:code>\n" + t[#t+1] = "</code>\n" elseif v.comment then - t[#t+1] = "\n<ldx:comment>\n" .. v.comment .. "\n</ldx:comment>\n" + t[#t+1] = "\n<comment>\n" .. v.comment .. "\n</comment>\n" else -- cannot happen end end - t[#t+1] = "\n</ldx:document>\n" + t[#t+1] = "\n</document>\n" return table.concat(t,"") end @@ -377,6 +379,8 @@ as the module to be used. The main conversion call is: --ldx]]-- +-- todo: assume usage of "mtxrun --script x-ldx", maybe make it mtx-ldx + if arg and arg[1] then ldx.convert(arg[1],arg[2]) end diff --git a/scripts/context/perl/cont_mis.pm b/scripts/context/perl/cont_mis.pm deleted file mode 100644 index 6bd449bf0..000000000 --- a/scripts/context/perl/cont_mis.pm +++ /dev/null @@ -1,69 +0,0 @@ -#D \module -#D [ file=cont\_mis.pm, -#D version=1999.05.05, -#D title=General modules, -#D subtitle=all kind of subs, -#D author=Hans Hagen, -#D date=\currentdate, -#D copyright={PRAGMA / Hans Hagen \& Ton Otten}] -#C -#C This module is part of the \CONTEXT\ macro||package and is -#C therefore copyrighted by \PRAGMA. See licen-en.pdf for -#C details. - -#D Not yet documented, source will be cleaned up. - -package cont_mis ; - -use strict ; - -my ($message, $separator, $content) ; - -format = -@>>>>>>>>>>>>>>>>>>>>> @ @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< -$message,$separator,$content -. - -sub report - { ($message, $separator, $content) = @_ ; write } - -sub crlf { print "\n" } -sub banner { crlf ; report (shift , '/', shift) ; crlf } -sub message { report (shift , ':', shift) } -sub help { report (shift , ' ', shift) } -sub status { message ('status' , shift) } -sub warning { message ('warning' , shift) } -sub error { message ('error' , shift) } -sub continue { message ('' , shift) } - -sub hex_color - { my ($r,$g,$b) = @_ ; - if ($r>1) { $r=0xffff } else { $r = 0xffff*$r } - if ($g>1) { $g=0xffff } else { $g = 0xffff*$g } - if ($b>1) { $b=0xffff } else { $b = 0xffff*$b } - local $_ = sprintf "%4x%4x%4x", $r, $g, $b ; - s/ /0/go ; - return $_ } - -sub InterfaceFound - { local $_ = shift ; - if (/^\%.*interface=(.*?)\b/) - { return $1 } - elsif (/\\(starttekst|stoptekst|startonderdeel)/) - { return 'nl' } - elsif (/\\(stelle|verwende|umgebung|benutze)/) - { return 'de' } - elsif (/\\(stel|gebruik|omgeving)/) - { return 'nl' } - elsif (/\\(use|setup|environment)/) - { return 'en' } - elsif (/(hoogte|breedte|letter)=/) - { return 'nl' } - elsif (/(height|width|style)=/) - { return 'en' } - elsif (/(hoehe|breite|schrift)=/) - { return 'de' } - else - { return '' } } - -1; diff --git a/scripts/context/perl/cont_set.pm b/scripts/context/perl/cont_set.pm deleted file mode 100644 index 41c62e754..000000000 --- a/scripts/context/perl/cont_set.pm +++ /dev/null @@ -1,670 +0,0 @@ -#D \module -#D [ file=cont\_set.pm, -#D version=1999.04.01, -#D title=General modules, -#D subtitle=showing \CONTEXT\ commands, -#D author=Hans Hagen, -#D date=\currentdate, -#D copyright={PRAGMA / Hans Hagen \& Ton Otten}, -#D suggestions={Tobias Burnus \& Taco Hoekater}] -#C -#C This module is part of the \CONTEXT\ macro||package and is -#C therefore copyrighted by \PRAGMA. See licen-en.pdf for -#C details. - -# todo: tacos speed patch - -#D As always: thanks to Taco and Tobias for testing this -#D module and providing suggestions and code snippets as -#D well as haunting bugs. - -package cont_set ; - -#D This module (package) deals with providing help information -#D about the \CONTEXT\ commands. The data needed is derived -#D from the setup files by \CONTEXT\ itself. The data is -#D stored in files with suffix \type {tws} (tex work setup). -#D This module introduces some subroutines: -#D -#D \starttabulatie[|Tl|p|] -#D \NC \type {set\_setup\_interface} \NC sets the primary interface -#D to search in \NC \NR -#D \NC \type {set\_setup\_title} \NC sets the title of the main -#D window title \NC \NR -#D \NC \type {setups\_found} \NC locate the \type {tws} files -#D using the \type {kpsewhich} -#D program \NC \NR -#D \NC \type {show\_setups} \NC allocate the radio buttons -#D that can be used to select a -#D command set \NC \NR -#D \NC \type {load\_setup(filename)} \NC load the names \type {tws} -#D file \NC \NR -#D \NC \type {load\_setups} \NC all found command files can -#D be loaded at once \NC \NR -#D \NC \type {setup\_found(filename)} \NC this routine returns~1 when -#D the file is loaded \NC \NR -#D \NC \type {update\_setup} \NC when we browse the list with -#D commands, this routine takes care -#D of updating the text area \NC \NR -#D \NC \type {change\_setup} \NC we can manually set the -#D command set we want to browse, -#D and this routine takes care of -#D this \NC \NR -#D \NC \type {show\_setup(command)} \NC context sensitive help can be -#D provided by calling this sub \NC \NR -#D \stoptabulatie -#D -#D First we load some packages and set some constants. - -use Tk ; -use Tk::ROText ; -use Config ; - -use strict; - -use subs qw/ update_setup / ; - -my $dosish = ($Config{'osname'} =~ /dos|win/i) ; -my $default_size = $dosish ? 9 : 12 ; - -my $textfont = "Courier $default_size " ; -my $userfont = "Courier $default_size italic" ; -my $buttonfont = "Helvetica $default_size bold " ; - -unless ($dosish) - { $textfont = "-adobe-courier-bold-r-normal--$default_size-120-75-75-m-70-iso8859-1" ; - $userfont = "-adobe-courier-bold-o-normal--$default_size-120-75-75-m-70-iso8859-1" ; - $buttonfont = "-adobe-helvetica-bold-r-normal--$default_size-120-75-75-p-69-iso8859-1" } - -my $s_vertical = 30 ; -my $s_horizontal = 72 ; -my $c_horizontal = 24 ; - -#D The main window is not resizable, but the text area and -#D command list will have scrollbars. - -my %lw ; # stack of lists - -my $mw = MainWindow -> new ( -title => 'ConTeXt commands' ) ; - -$mw -> withdraw() ; $mw -> resizable ('y', 'y') ; - -sub SetupWindow { return $mw } ; - -my $bw = $mw -> Frame () ; # buttons -my $tw = $mw -> Frame () ; # sw + fw -my $fw = $tw -> Frame () ; # string + list - -my $request = $fw -> Entry ( -font => $textfont , - -background => 'ivory1' , - -width => $c_horizontal ) ; - -my $cw = $fw -> Scrolled ( 'Listbox' , - -scrollbars => 'e' , - -font => $textfont , - -width => $c_horizontal , - -selectbackground => 'gray' , - -background => 'ivory1' , - -selectmode => 'browse' ) ; - -$cw -> pack ( -side => 'bottom' , -fill => 'both' , -expand => 1 ) ; -$request -> pack ( -side => 'top' , -fill => 'x' ) ; - -my $sw = $tw -> Scrolled ( 'ROText' , - -scrollbars => 'se' , - -height => $s_vertical , - -width => $s_horizontal , - -wrap => 'none' , - -background => 'ivory1' , - -font => $textfont ) ; - - -#D And the whole bunch of widgets are packed in the main -#D window. - -sub pack_them_all - { $sw -> pack ( -side => 'left' , -fill => 'both' , -expand => 1 ) ; - $fw -> pack ( -side => 'right' , -fill => 'y' , -expand => 0 ) ; - $bw -> pack ( -side => 'top' , -fill => 'x' , -anchor => 'w' , -expand => 1 ) ; - $tw -> pack ( -side => 'bottom', -fill => 'both' , -expand => 1 ) } - -sub unpack_them_all - { } - -pack_them_all ; - -#D We scan for available setup files, with suffix \type {tws}. -#D These should be somewhere on the system, grouped in one -#D directory. At least the english file \type {cont-en.tws} -#D should be found. - -my $tws_path = '' ; -my @setup_files = ('cont-en.tws') ; -my $setup_file = $setup_files[0] ; -my $setup_interface = 'en' ; -my $old_setup_file = '' ; - -sub set_setup_interface - { $setup_interface = shift } - -sub set_setup_title - { $mw -> configure ( -title => shift ) } - -sub setups_found - { $tws_path = `kpsewhich --format="other text files" --progname=context cont-en.tws` ; - $tws_path =~ s/cont-en\.tws.*// ; - chop $tws_path ; - @setup_files = glob ("$tws_path*.tws") ; - if (@setup_files) - { foreach (@setup_files) { s/\.tws// ; s/.*\/// } - $setup_file = $setup_files[0] ; - return 1 } - else - { return 0 } } - -#D A hide button - -sub show_hide_button - { my $hb = $bw -> Button ( -text => "hide" , - -font => $buttonfont , - -command => \&hide_widget ) ; - $hb -> pack ( -padx => '2p', - -pady => '2p', - -side => 'right' ) } - -sub hide_widget - { $mw -> withdraw() } - -#D The setup files can be shown and chosen. - -sub show_setups - { unpack_them_all ; - foreach (@setup_files) - { $lw{$_} = $bw -> Radiobutton ( -text => lc $_ , - -value => $_ , - -font => $buttonfont , - -selectcolor => 'ivory1' , - -indicatoron => 0 , - -command => \&change_setup , - -variable => \$setup_file ) ; - $lw{$_} -> pack ( -padx => '2p', - -pady => '2p', - -side => 'left' ) } - pack_them_all } - -$cw -> bind ('<B1-Motion>', \&update_setup ) ; -$cw -> bind ('<1>' , \&update_setup ) ; -$cw -> bind ('<Key>' , \&update_setup ) ; - -$sw -> tag ('configure', 'user' , -font => $userfont ) ; -$sw -> tag ('configure', 'command' , -foreground => 'green3' ) ; -$sw -> tag ('configure', 'variable' , -font => $userfont ) ; -$sw -> tag ('configure', 'default' , -underline => 1 ) ; -$sw -> tag ('configure', 'symbol' , -foreground => 'blue3' ) ; -$sw -> tag ('configure', 'or' , -foreground => 'yellow3' ) ; -$sw -> tag ('configure', 'argument' , -foreground => 'red3' ) ; -$sw -> tag ('configure', 'par' , -lmargin1 => '4m' , - -lmargin2 => '6m' ) ; - -my %setups ; -my %commands ; -my %loadedsetups ; -my %positions ; -my %crosslinks ; - -my $current_setup = '' ; - -#D Setups are organized in files called \type {*.tws} and -#D alike. Several files can be loaded simultaneously. When -#D loading, we grab whole paragraphs. The variables and values -#D belonging to a command, are stored in the hash table \type -#D {setups}, one per language. The command templates are -#D stored in \type {commands}. -#D -#D A \type {tws} file is generated by \CONTEXT\ from the setup -#D definition files. Only \CONTEXT\ knows the current meaning -#D of commands and keywords. The files are generating by -#D simply saying something like: -#D -#D \starttypen -#D texexec --interface=en setupd -#D texexec --interface=de setupd -#D texexec --interface=nl setupd -#D texexec --interface=cz setupd -#D texexec --interface=it setupd -#D \stoptypen -#D -#D This results in files formatted as: -#D -#D \starttypen -#D startsetup -#D com:setupcolors -#D typ:vars/ -#D var:state:start,stop,global,local: -#D var:conversion:yes,no,always: -#D var:reduction:yes,no: -#D var:rgb:yes,no: -#D var:cmyk:yes,no: -#D stopsetup -#D \stoptypen -#D -#D This format can be stored rather efficient and parsed rather -#D fast. What more do we need. - -sub load_setup - { my $filename = shift ; - unless (keys %{$commands{$filename}}) - { local $/ = 'stopsetup' ; # in plaats van '' ivm unix ; (taco) - $current_setup = '' ; - if (open(SETUP, "$tws_path$filename.tws" )) - { my $position = 0 ; - while (<SETUP>) - { chomp ; - s/startsetup//mso ; - s/stopsetup//mso ; # redundant geworden - s/\r\n //gms ; # in plaats van s/ //gms ; (taco) - s/com\:(.*?)\:\s(.*)//mso ; - my $string = $1 ; - my $command = $1 ; - my $setup = $2 ; - ++$position ; - $string =~ s/(.*?)\<\<(.*?)\>\>(.*?)/$1$2$3/o ; - $setups {$filename}{$string} = $setup ; - $commands {$filename}{$string} = $command ; - $positions {$filename}{$string} = $position ; - $crosslinks{$filename}[$position] = $string } - close (SETUP) } } - my @list = sort {lc $a cmp lc $b} keys %{$commands{$filename}} ; - $cw -> delete ('0.0', 'end') ; - $cw -> insert ('end', @list) ; - $cw -> selectionSet ('0.0', '0.0') ; - $cw -> activate ('0.0') ; - $setup_file = $filename ; - update_setup } - -sub load_setups - { foreach my $setup (@setup_files) { load_setup ($setup) } ; - $mw -> deiconify() } - -#D The core of this module deals with transforming the -#D definitions like shown earlier. Details on the format -#D can be found in the file \type {setupd.tex}. We use the -#D \type {Tk::Text} automatic hanging identation features. -#D The next subs are examples of the kind you write once -#D and never look at again. - -my @arguments = () ; -my $nested_setup = 0 ; -my $continue_setup = 0 ; -my $argument = 0 ; -my $stopsuffix = '' ; -my $stopcommand = '' ; - -my %arg ; - -$arg {repeat} = '//n*/' ; -$arg {arg} = 'argument/{/.../}' ; -$arg {args} = 'argument/{/..,...,../}' ; -$arg {dis} = 'argument/$$/.../$$' ; -$arg {idx} = 'argument/{/.../}' ; -$arg {idxs} = 'argument/{/..+...+../}' ; -$arg {mat} = 'argument/$/...:$' ; -$arg {nop} = '//.../' ; -$arg {fil} = '//.../' ; -$arg {pos} = 'symbol/(/.../)' ; -$arg {poss} = 'symbol/(/...,.../)' ; -$arg {sep} = 'command//\\\\/' ; -$arg {ref} = 'symbol/[/ref/]' ; -$arg {refs} = 'symbol/[/ref,../]' ; -$arg {val} = 'symbol/[/.../]' ; -$arg {vals} = 'symbol/[/..,...,../]' ; -$arg {var} = 'symbol/[/..=../]' ; -$arg {vars} = 'symbol/[/..,..=..,../]' ; -$arg {cmd} = 'command//\cmd/' ; -$arg {dest} = 'symbol/[/..ref/]' ; -$arg {dests} = 'symbol/[/..,..refs,../]' ; -$arg {trip} = 'symbol/[/x:y:z=/]' ; -$arg {trips} = 'symbol/[/x:y:z=,../]' ; -$arg {wrd} = 'argument/{/.../}' ; -$arg {wrds} = 'argument/{/......./}' ; -$arg {par} = 'command//\par/' ; -$arg {stp} = '//stop/' ; -$arg {par} = 'command///' ; - -sub show_command - { my $command = shift ; - local $_ = $commands{$setup_file}{$command} ; - if ($command eq $_) - { $sw -> insert ('end', "\\$command", 'command' ) } - elsif (/(.*?)\<\<(.*?)\>\>(.*?)/o) - { $sw -> insert ('end', "\\", 'command' ) ; - if ($1) { $sw -> insert ('end', $1, 'command' ) } - if ($2) { $sw -> insert ('end', $2, ['command','user'] ) } - if ($3) { $sw -> insert ('end', $3, 'command' ) } - $stopsuffix = $2 } } - -sub show_left_argument - { local $_ = shift ; - my @thearg = split (/\//, $arg{$arguments[$_]}) ; - $sw -> insert ('end', $thearg[1], ['par',$thearg[0]] ) } - -sub show_middle_argument - { local $_ = shift ; - my @thearg = split (/\//, $arg{$arguments[$_]}) ; - if ($thearg[1]) - { $sw -> insert ('end', $thearg[2], 'par' ) } - else - { $sw -> insert ('end', $thearg[2], ['par',$thearg[0]] ) } } - -sub show_right_argument - { local $_ = shift ; - my @thearg = split (/\//, $arg{$arguments[$_]}) ; - $sw -> insert ('end', $thearg[3], ['par',$thearg[0]] ) ; - ++$argument } - -sub show_reference - { if (($nested_setup<=1)&&(defined($arguments[$argument]))) - { if ($arguments[$argument]=~/ref/) - { $sw -> insert ('end', "\n" ) ; - show_left_argument ($argument) ; - show_middle_argument ($argument) ; - show_right_argument ($argument) } } } - -sub show_stop_command - { my $before_stop = shift ; - if ($stopcommand) - { if ($stopsuffix) - { $sw -> insert ('end', '\\stop', 'command' ) ; - $sw -> insert ('end', $stopsuffix, ['command','user'] ) } - else - { $sw -> insert ('end', $stopcommand, 'command' ) } } } - -sub show_whatever_left - { while ($argument<@arguments) - { $sw -> insert ('end', "\n" ) ; - show_left_argument ($argument) ; - show_middle_argument ($argument) ; - show_right_argument ($argument) ; - ++$argument } - if ($stopcommand) - { $sw -> insert ('end', "\n...\n...\n...\n", 'par') ; - show_stop_command } } - -sub do_update_setup # type: 0=all 1=vars 2=vals - { my ($command, $type) = @_ ; - my $setup = $setups{$setup_file}{$command} ; - my $default = '' ; - my $key = '' ; - my $meaning = '' ; - my @values = () ; - local $_ ; - ++$nested_setup ; - while ($setup=~/(typ|var|val|ivr|ivl)\:(.*?)\:\s/mgo) - { $key = $1 ; - $meaning = $2 ; - if (($key=~/var/o)&&($type!=2)) - { $_ = $meaning ; s/(.*?)\:(.*?)\:(.*)//o ; - if (($nested_setup>1)&&(!$2)) { next } - $key = $1 ; - if ($3) { $default = $3 } else { $default = '' } - $_= $2 ; s/\s//go ; @values = split (/,/,$_) ; - if ($continue_setup) - { $sw -> insert ('end', ",\n ", 'par') } - else - { $continue_setup = 1 ; - $sw -> insert ('end', "\n", 'par') ; - show_left_argument($argument) } - $sw -> insert ('end', $key , 'par' ) ; - $sw -> insert ('end', '=', ['symbol','par'] ) ; - #while (1) - while (@values) - { my $value = shift @values ; - if ($value =~ /^\*/o) - { $value =~ s/^\*//o ; - $sw -> insert ('end', lc $value, ['variable','par'] ) } - elsif ($value eq $default) - { $sw -> insert ('end', $value, ['default','par'] ) } - else - { $sw -> insert ('end', $value, 'par' ) } - if (@values) - { $sw -> insert ('end', '|' , ['or','par'] ) } - else - { last } } } - elsif (($key=~/val/o)&&($type!=1)) - { $_ = $meaning ; s/(.*)\:(.*)//o ; - if (($nested_setup>1)&&(!$2)) { next } - $_ = $1 ; s/\s//go ; @values = split (/,/,$_) ; - if ($2) { $default = $2 } else { $default = '' } - if ($continue_setup) - { $continue_setup = 0 ; - show_right_argument($argument) } - $sw -> insert ('end', "\n" , 'par') ; - show_left_argument($argument) ; - #while (1) - while (@values) - { unless (@values) { last } - my $value = shift (@values) ; - if ($value =~ /^\*/o) - { $value =~ s/^\*//o ; - $sw -> insert ('end', lc $value, ['variable','par'] ) } - elsif ($value eq $default) - { $sw -> insert ('end', $value, ['default','par'] ) } - else - { $sw -> insert ('end', $value, 'par' ) } - if (@values) - { $sw -> insert ('end', ', ', 'par' ) } - else - { last } } - show_right_argument($argument) } - elsif ($key=~/typ/o) - { if ($nested_setup==1) - { show_command ($command) ; - my $arguments = $meaning ; - if ($arguments=~/stp/) - { $_ = $command ; - s/start(.*)/$1/o ; - $stopcommand = "\\stop$_" ; - $arguments =~ s/stp//go } - @arguments = split (/\//,$arguments) ; - if (@arguments) - { for (my $i=0;$i<@arguments;$i++) - { show_left_argument ($i) ; - show_middle_argument ($i) ; - show_right_argument ($i) } - if ($stopcommand) - { $sw -> insert ('end', ' ... ') ; - show_stop_command } - $sw -> insert ('end', "\n\n") ; - show_command ($command) } - $argument = 0 ; - $continue_setup = 0 } } - elsif ($key=~/ivr/o) - { $meaning =~ s/(.*)\:(.*)//o ; - do_update_setup ($1,1) } - elsif ($key=~/ivl/o) - { $meaning =~ s/(.*)\:(.*)//o ; - do_update_setup ($1,2) } - show_reference } - --$nested_setup ; - if (($continue_setup)&&(!$nested_setup)) - { show_right_argument ; - show_whatever_left } } - -#D Now the real work is done, we only have to define a few -#D housekeeping routines. The next sub adapts the text area -#D to the current selected command and normally is bound to -#D the list browsing commands. - -sub update_setup - { $old_setup_file = $setup_file ; - if (keys %{$commands{$setup_file}}) - { my $key ; - unless ($cw->curselection) - { $cw -> selectionSet('0.0','0.0') } - $key = $cw -> get($cw->curselection) ; - if ($current_setup ne $key) - { $current_setup = $key ; - $sw -> delete ('1.0', 'end' ) ; - $nested_setup = 0 ; - $argument = 0 ; - $stopcommand = '' ; - $stopsuffix = '' ; - do_update_setup ($key,0) ; - $mw -> raise ; - $mw -> focus } } } - -#D In editors we want to provide context sensitive help -#D information. The next sub first tries to locate the -#D commands asked for in the setup data currently selected, -#D and when not found takes a look at all the loaded files. - -sub show_setup - { my $asked_for = shift ; - unless ($asked_for) { return } - my $found = 0 ; - $asked_for =~ s/^\\// ; - if ($setup_interface) - { $found = 0 ; - foreach my $name (@setup_files) - { if (($name=~/\-$setup_interface/)&&(exists($commands{$name}{$asked_for}))) - { $found = 1 ; - $setup_file = $name ; - last } } } - if (!($found)&&(exists($commands{$setup_file}{$asked_for}))) - { $found = 1 } - else - { $found = 0 ; - foreach my $name (@setup_files) - { if (exists($commands{$name}{$asked_for})) - { $found = 1 ; - $setup_file = $name ; - last } } } - if ($found) - { my @list = sort {lc $a cmp lc $b} keys %{$commands{$setup_file}} ; - $cw -> delete ('0.0', 'end') ; - $cw -> insert ('end', @list) ; - $found = 0 ; - foreach (@list) { if ($_ eq $asked_for) { last } ++$found } - my $index = "$found.0" ; - $cw -> selectionSet ($index, $index) ; - $cw -> activate ($index) ; - $cw -> see ($index) ; - update_setup ; - $mw -> raise ; - $mw -> focus } } - -#D Whenever a new set of commands is selected (by means of the -#D buttons on top the screen) the list and text are to be -#D updated. - -sub change_setup - { my $command = '' ; - if ($old_setup_file) - { unless ($cw->curselection) - { $cw -> selectionSet('0.0','0.0') } - $command = $cw -> get($cw->curselection) ; - my $position = $positions{$old_setup_file}{$command} ; - $command = $crosslinks{$setup_file}[$position] } - load_setup($setup_file) ; - my @list = sort {lc $a cmp lc $b} keys %{$commands{$setup_file}} ; - $cw -> delete ('0.0', 'end') ; - $cw -> insert ('end', @list) ; - if ($command) - { show_setup($command) } - else - { $cw -> selectionClear ('0.0','end') ; - $cw -> selectionSet ('0.0', '0.0') ; - $cw -> see ('0.0') ; - $cw -> activate ('0.0') } - update_setup ; - $mw -> raise ; - $mw -> focus } - -#D Sometimes we want to make sure the dat is loaded indeed: - -sub setup_found - { my $filename = shift ; - if (-e "$tws_path$filename.tws") - { $setup_file = $filename ; - return 1 } - else - { return 0 } } - -#D The next feature is dedicated to Tobias, who suggested -#D it, and Taco, who saw it as yet another proof of the -#D speed of \PERL. It's also dedicated to Ton, who needs it -#D for translating the big manual. - -sub handle_request - { my $index = $cw -> index('end') ; - unless ($index) { return } - my $req = $request -> get ; - unless ($req) { return } - $req =~ s/\\//o ; - $req =~ s/\s//go ; - $request -> delete('0','end') ; - $request -> insert('0',$req) ; - unless ($req) { return } - my ($l,$c) = split (/\./,$index) ; - for (my $i=0;$i<=$l;$i++) - { $index = "$i.0" ; - my $str = $cw -> get ($index, $index) ; - if ($str =~ /^$req/) - { $cw -> selectionClear ('0.0','end') ; - $cw -> selectionSet ($index, $index) ; - $cw -> activate ($index) ; - $cw -> see ($index) ; - update_setup ; - $mw -> raise ; - $mw -> focus ; - return } } } - -$request -> bind ('<Return>', sub { handle_request } ) ; - -sub insert_request - { my ($self, $chr) = @_ ; - if ($self ne $request) - { $request -> insert ('end', $chr) } - handle_request } - -foreach my $chr ('a'..'z','A'..'Z') - { $mw -> bind ( "<KeyPress-$chr>", sub { insert_request(shift, $chr) } ) } - -$mw -> bind ( "<backslash>", sub { insert_request(shift, "\\") } ) ; - -sub delete_request - { my $self = shift ; - if ($self ne $request) - { my $to = $request -> index ('end') ; - my $from = $to - 1 ; - if ($from<0) { $from = 0 } - $request -> delete ($from,$to) } - handle_request } - -$mw -> bind ( "<BackSpace>", sub { delete_request } ) ; - -sub new_request - { $request -> delete (0,'end') ; - handle_request } - -$mw -> bind ( "<space>", sub { new_request } ) ; - -#D Just in case: - -sub raise_setup - { $mw -> raise } - -sub dont_exit - { $mw -> protocol( 'WM_DELETE_WINDOW' => sub { } ) } - -#D An example use is: -#D -#D \starttypen -#D load_setup ("cont-$nl") ; -#D show_setup ('omlijnd') ; -#D MainLoop () ; -#D \stoptypen -#D -#D Now everything is done, we return 1: - -1 ; diff --git a/scripts/context/perl/path_tre.pm b/scripts/context/perl/path_tre.pm deleted file mode 100644 index 546afcd27..000000000 --- a/scripts/context/perl/path_tre.pm +++ /dev/null @@ -1,36 +0,0 @@ -#D \module -#D [ file=path\_tre.pm, -#D version=1999.05.05, -#D title=Path modules, -#D subtitle=selecting a path, -#D author=Hans Hagen, -#D date=\currentdate, -#D copyright={PRAGMA / Hans Hagen \& Ton Otten}] -#C -#C This module is part of the \CONTEXT\ macro||package and is -#C therefore copyrighted by \PRAGMA. See licen-en.pdf for -#C details. - -#D Not yet documented, source will be cleaned up. - -package Tk::path_tre ; - -use Tk; -require Tk::DirTree ; - -use base qw(Tk::DirTree); -use strict; - -Construct Tk::Widget 'PathTree'; - -sub ClassInit - { my ($class,$mw) = @_ ; - return $class -> SUPER::ClassInit ($mw) } - -sub dirnames - { my ( $w, $dir ) = @_ ; - unless ($dir=~/\//) { $dir .= '/' } - my @names = $w->Callback("-dircmd", $dir, $w->cget("-showhidden")); - return( @names ) } - -__END__ diff --git a/scripts/context/perl/texexec.pl b/scripts/context/perl/texexec.pl deleted file mode 100644 index fb564bbd5..000000000 --- a/scripts/context/perl/texexec.pl +++ /dev/null @@ -1,3294 +0,0 @@ -eval '(exit $?0)' && eval 'exec perl -w -S $0 ${1+"$@"}' && eval 'exec perl -w -S $0 $argv:q' - if 0 ; - -#D \module -#D [ file=texexec.pl, -#D version=2004.08.29, -#D title=running \ConTeXt, -#D subtitle=\TEXEXEC, -#D author=Hans Hagen, -#D date=\currentdate, -#D copyright={PRAGMA / Hans Hagen \& Ton Otten}] -#C -#C This module is part of the \CONTEXT\ macro||package and is -#C therefore copyrighted by \PRAGMA. See readme.pdf for -#C details. - -# Thanks to Tobias Burnus for the german translations. -# Thanks to Thomas Esser for hooking it into web2c -# Thanks to Taco Hoekwater for suggesting improvements -# Thanks to Wybo Dekker for the advanced help interface and making it strict -# Thanks to Fabrice Popineau for windows path trickery and fixes - -# (I still have to completely understand the help code -) - -#D We started with a hack provided by Thomas Esser. This -#D expression replaces the unix specific line \type -#D {#!/usr/bin/perl}. - -#D History has learned that writing wrappers like this is quite painful -#D because of differences between platforms, changes in the tex command -#D line flags (fmt), default behaviour (e.g. 8 bit), and the assumption -#D that everyone runs the same tex and that distributers take care of -#D everything. Well, the result is a messy script like this ... Sorry. - -use strict ; - -my $OriginalArgs = join(' ',@ARGV) ; - -#~ use warnings ; # strange warnings, todo - -# todo: second run of checksum of mp file with --nomprun changes -# todo: warning if no args -# todo: <<<< in messages -# todo: cleanup - -use Cwd; -use Time::Local; -use Config; -use Getopt::Long; -use Class::Struct; # needed for help subsystem -use FindBin; -use File::Compare; -use File::Temp; -use Digest::MD5; - -#~ use IO::Handle; autoflush STDOUT 1; - -my %ConTeXtInterfaces; # otherwise problems with strict -my %ResponseInterface; # since i dunno how to allocate else - -my %Help; - -#D In this script we will launch some programs and other -#D scripts. \TEXEXEC\ uses an ini||file to sort out where -#D those programs are stored. Two boolean variables keep -#D track of the way to call the programs. In \TEXEXEC, -#D \type {$dosish} keeps track of the operating system. -#D It will be no surprise that Thomas Esser provided me -#D the neccessary code to accomplish this. - -$ENV{"MPXCOMMAND"} = "0"; # otherwise loop - -my $TotalTime = time; - -# start random seed hack -# -# This hack is needed since tex has 1 minute resolution, so -# we need to be smaller about 1440 (== 24*60 == tex's max time) -# in which case (david a's) random calculator will overflow. - -# my ( $sec, $min, $rest ) = gmtime; -# my $RandomSeed = $min * 60 + $sec; -# -# # i have to look up the mod function -) -# -# if ( $RandomSeed > 2880 ) { $RandomSeed -= 2880 } -# if ( $RandomSeed > 1440 ) { $RandomSeed -= 1440 } - -my ($sec, $min) = gmtime; -my $RandomSeed = ($min * 60 + $sec) % 2880; # else still overflow - -# See usage of $Random and $RandomSeed later on. -# -# end random seed hack - -my $dosish = ( $Config{'osname'} =~ /^(ms)?dos|^os\/2|^mswin/i ); -my $escapeshell = ( ($ENV{'SHELL'}) && ($ENV{'SHELL'} =~ m/sh/i )); - -my $TeXUtil = 'texutil'; -my $TeXExec = 'texexec'; -my $MetaFun = 'metafun'; -my $MpToPdf = 'mptopdf'; - -$Getopt::Long::passthrough = 1; # no error message -$Getopt::Long::autoabbrev = 1; # partial switch accepted - -my $AddEmpty = ''; -my $Alone = 0; -my $Optimize = 0; -my $ForceTeXutil = 0; -my $Arrange = 0; -my $BackSpace = '0pt'; -my $Background = ''; -my $CenterPage = 0; -my $ConTeXtInterface = 'unknown'; -my $Convert = ''; -my $DoMPTeX = 0; -my $DoMPXTeX = 0; -my $EnterBatchMode = 0; -my $EnterNonStopMode = 0; -my $Environments = ''; -my $Modules = ''; -my $FastMode = 0; -my $FinalMode = 0; -my $Format = ''; -my $MpDoFormat = ''; -my $HelpAsked = 0; -my $Version = 0; -my $MainBodyFont = 'standard'; -my $MainLanguage = 'standard'; -my $MainResponse = 'standard'; -my $MakeFormats = 0; -my $Markings = 0; -my $Mode = ''; -my $NoArrange = 0; -my $NoDuplex = 0; -my $NOfRuns = 8; -my $NoMPMode = 0; -my $NoMPRun = 0; -my $NoBanner = 0; -my $AutoMPRun = 0; -my $OutputFormat = 'standard'; -my $Pages = ''; -my $PageScale = '1000'; # == 1.0 -my $PaperFormat = 'standard'; -my $PaperOffset = '0pt'; -my $PassOn = ''; -my $PdfArrange = 0; -my $PdfSelect = 0; -my $PdfCombine = 0; -my $PdfOpen = 0; -my $PdfClose = 0; -my $AutoPdf = 0; -my $UseXPdf = 0; -my $PrintFormat = 'standard'; -my $ProducePdfT = 0; -my $ProducePdfM = 0; -my $ProducePdfX = 0; -my $ProducePdfXTX = 0; -my $ProducePs = 0; -my $Input = ""; -my $Result = ''; -my $Suffix = ''; -my $RunOnce = 0; -my $Selection = ''; -my $Combination = '2*4'; -my $SilentMode = 0; -my $TeXProgram = ''; -my $TeXTranslation = ''; -my $TextWidth = '0pt'; -my $TopSpace = '0pt'; -my $TypesetFigures = 0; -my $ForceFullScreen = 0; -my $ScreenSaver = 0; -my $TypesetListing = 0; -my $TypesetModule = 0; -my $UseColor = 0; -my $Verbose = 0; -my $PdfCopy = 0; -my $PdfTrim = 0; -my $LogFile = ""; -my $MpyForce = 0; -my $InpPath = ""; -my $AutoPath = 0; -my $RunPath = ""; -my $Arguments = ""; -my $Pretty = 0; -my $SetFile = ""; -my $TeXTree = ""; -my $TeXRoot = ""; -my $Purge = 0; -my $Separation = ""; -my $ModeFile = ""; -my $GlobalFile = 0; -my $AllPatterns = 0; -my $ForceXML = 0; -my $Random = 0; -my $Filters = ''; -my $NoMapFiles = 0 ; -my $Foxet = 0 ; -my $TheEnginePath = 0 ; -my $Paranoid = 0 ; -my $NotParanoid = 0 ; -my $BoxType = '' ; -my $Local = '' ; - -my $TempDir = '' ; - -my $StartLine = 0 ; -my $StartColumn = 0 ; -my $EndLine = 0 ; -my $EndColumn = 0 ; - -my $MpEngineSupport = 0 ; # not now, we also need to patch executemp in context itself - -# makempy : - -my $MakeMpy = ''; - -&GetOptions( - "arrange" => \$Arrange, - "batch" => \$EnterBatchMode, - "nonstop" => \$EnterNonStopMode, - "color" => \$UseColor, - "centerpage" => \$CenterPage, - "convert=s" => \$Convert, - "environments=s" => \$Environments, - "usemodules=s" => \$Modules, - "xml" => \$ForceXML, - "xmlfilters=s" => \$Filters, - "fast" => \$FastMode, - "final" => \$FinalMode, - "format=s" => \$Format, - "mpformat=s" => \$MpDoFormat, - "help" => \$HelpAsked, - "version" => \$Version, - "interface=s" => \$ConTeXtInterface, - "language=s" => \$MainLanguage, - "bodyfont=s" => \$MainBodyFont, - "results=s" => \$Result, - "response=s" => \$MainResponse, - "make" => \$MakeFormats, - "mode=s" => \$Mode, - "module" => \$TypesetModule, - "figures=s" => \$TypesetFigures, - "fullscreen" => \$ForceFullScreen, - "screensaver" => \$ScreenSaver, - "listing" => \$TypesetListing, - "mptex" => \$DoMPTeX, - "mpxtex" => \$DoMPXTeX, - "noarrange" => \$NoArrange, - "nomp" => \$NoMPMode, - "nomprun" => \$NoMPRun, - "nobanner" => \$NoBanner, - "automprun" => \$AutoMPRun, - "once" => \$RunOnce, - "output=s" => \$OutputFormat, - "pages=s" => \$Pages, - "paper=s" => \$PaperFormat, - "paperformat=s" => \$PaperFormat, - "passon=s" => \$PassOn, - "path=s" => \$InpPath, - "autopath" => \$AutoPath, - "pdf" => \$ProducePdfT, - "pdm" => \$ProducePdfM, - "dpm" => \$ProducePdfM, - "pdx" => \$ProducePdfX, - "dpx" => \$ProducePdfX, - "xtx" => \$ProducePdfXTX, - "ps" => \$ProducePs, - "pdfarrange" => \$PdfArrange, - "pdfselect" => \$PdfSelect, - "pdfcombine" => \$PdfCombine, - "pdfcopy" => \$PdfCopy, - "pdftrim" => \$PdfTrim, - "scale=s" => \$PageScale, - "selection=s" => \$Selection, - "combination=s" => \$Combination, - "noduplex" => \$NoDuplex, - "offset=s" => \$PaperOffset, - "paperoffset=s" => \$PaperOffset, - "backspace=s" => \$BackSpace, - "topspace=s" => \$TopSpace, - "markings" => \$Markings, - "textwidth=s" => \$TextWidth, - "addempty=s" => \$AddEmpty, - "background=s" => \$Background, - "logfile=s" => \$LogFile, - "print=s" => \$PrintFormat, - "suffix=s" => \$Suffix, - "runs=s" => \$NOfRuns, - "silent" => \$SilentMode, - "tex=s" => \$TeXProgram, - "verbose" => \$Verbose, - "alone" => \$Alone, - "optimize" => \$Optimize, - "texutil" => \$ForceTeXutil, - "mpyforce" => \$MpyForce, - "input=s" => \$Input, - "arguments=s" => \$Arguments, - "pretty" => \$Pretty, - "setfile=s" => \$SetFile, # obsolete - "purge" => \$Purge, - #### yet undocumented ################# - "runpath=s" => \$RunPath, - "random" => \$Random, - "makempy=s" => \$MakeMpy, - "allpatterns" => \$AllPatterns, - "separation=s" => \$Separation, - "textree=s" => \$TeXTree, - "texroot=s" => \$TeXRoot, - "translate=s" => \$TeXTranslation, - "pdfclose" => \$PdfClose, - "pdfopen" => \$PdfOpen, - "autopdf" => \$AutoPdf, - "xpdf" => \$UseXPdf, - "modefile=s" => \$ModeFile, # additional modes file - "globalfile" => \$GlobalFile, - "nomapfiles" => \$NoMapFiles, - "foxet" => \$Foxet, - "engine" => \$TheEnginePath, - "paranoid" => \$Paranoid, - "notparanoid" => \$NotParanoid, - "boxtype=s" => \$BoxType, # media art crop bleed trim - "local" => \$Local, - #### unix is unsafe (symlink viruses) - "tempdir=s" => \$TempDir, - #### experiment - "startline=s" => \$StartLine, - "startcolumn=s" => \$StartColumn, - "endline=s" => \$EndLine, - "endcolumn=s" => \$EndColumn -); # don't check name - -if ($Foxet) { - $ProducePdfT = 1 ; - $ForceXML = 1 ; - $Modules = "foxet" ; - $Purge = 1 ; -} - -# a set file (like blabla.bat) can set paths now - -if ( $SetFile ne "" ) { load_set_file( $SetFile, $Verbose ); $SetFile = "" } - -# later we will do a second attempt. - -$SIG{INT} = "IGNORE"; - -if ( $ARGV[0] && $ARGV[0] =~ /\.mpx$/io ) { # catch -tex=.... bug in mpost - $TeXProgram = ''; - $DoMPXTeX = 1; - $NoMPMode = 1; -} - -#### - -if ($Version) { - $Purge = 1 ; - } - -#### - -if ($Paranoid) { - $ENV{shell_escape} = 'f' ; - $ENV{openout_any} = 'p' ; - $ENV{openin_any} = 'p' ; -} elsif ($NotParanoid) { - $ENV{shell_escape} = 't' ; - $ENV{openout_any} = 'p' ; - $ENV{openin_any} = 'a' ; -} - -if (defined $ENV{openin_any} && $ENV{openin_any} eq 'p') { - $Paranoid = 1 ; # extra test in order to set readlevel -} - -if ((defined $ENV{shell_escape} && $ENV{shell_escape} eq 'f') || - (defined $ENV{SHELL_ESCAPE} && $ENV{SHELL_ESCAPE} eq 'f')) { - $AutoMPRun = 1 ; -} - -if ($ScreenSaver) { - $ForceFullScreen = 1; - $TypesetFigures = 'c'; - $ProducePdfT = 1; - $Purge = 1; -} - -if ( $DoMPTeX || $DoMPXTeX ) { - $RunOnce = 1; - $ProducePdfT = 0; - $ProducePdfX = 0; - $ProducePdfM = 0; - $ProducePdfXTX = 0; - $ProducePs = 0; -} - -if ( $PdfArrange || $PdfSelect || $PdfCopy || $PdfTrim || $PdfCombine ) { - $ProducePdfT = 1; - $RunOnce = 1; -} - -if ($ProducePdfT) { $OutputFormat = "pdftex" } -elsif ($ProducePdfM) { $OutputFormat = "dvipdfm" } -elsif ($ProducePdfX) { $OutputFormat = "dvipdfmx" } -elsif ($ProducePdfXTX) { $OutputFormat = "xetex" } -elsif ($ProducePs) { $OutputFormat = "dvips" } - -if ( $ProducePdfXTX ) { - $TeXProgram = 'xetex' ; # ignore the default pdfetex engine - $PassOn .= ' -no-pdf ' ; # Adam Lindsay's preference -} - -if ($AutoPdf) { - $PdfOpen = $PdfClose = 1 ; -} - -my $PdfOpenCall = "" ; - -if ($PdfOpen) { - $PdfOpenCall = "pdfopen --file" ; -} - -if ($UseXPdf && !$dosish) { - $PdfOpenCall = "xpdfopen" ; -} - -# this is our hook into paranoid path extensions, assumes that -# these three vars are part of path specs in texmf.cnf - -foreach my $i ('TXRESOURCES','MPRESOURCES','MFRESOURCES') { - foreach my $j ($RunPath,$InpPath) { - if ($j ne '') { - if ($ENV{$i} ne '') { - $ENV{$i} = $ENV{$i} . ',' . $j ; - } else { - $ENV{$i} = $j ; - } - } - } -} - -if ( $RunOnce || $Pages || $TypesetFigures || $TypesetListing ) { $NOfRuns = 1 } - -if ( ( $LogFile ne '' ) && ( $LogFile =~ /\w+\.log$/io ) ) { - open( LOGFILE, ">$LogFile" ); - *STDOUT = *LOGFILE; - *STDERR = *LOGFILE; -} - -my $Program = " TeXExec 5.4.3 - ConTeXt / PRAGMA ADE 1997-2005"; - -print "\n$Program\n\n"; - -if ($Verbose) { print " current path : " . cwd . "\n" } - -my $pathslash = '/'; -if ( $FindBin::Bin =~ /\\/ ) { $pathslash = "\\" } -my $cur_path = ".$pathslash"; - -# we need to handle window's "Program Files" path (patch by Fabrice P) - -my $own_path = "$FindBin::Bin/"; -my $own_type = $FindBin::Script; -my $own_quote = ( $own_path =~ m/^[^\"].* / ? "\"" : "" ); -my $own_stub = ""; - -if ( $own_type =~ /(\.pl|perl)/oi ) { $own_stub = "perl " } - -if ( $own_type =~ /(\.(pl|bin|exe))$/io ) { $own_type = $1 } -else { $own_type = '' } - -sub checked_path { - my $path = shift; - if ( ( defined($path) ) && ( $path ne '' ) ) { - $path =~ s/[\/\\]/$pathslash/go; - $path =~ s/[\/\\]*$//go; - $path .= $pathslash; - } else { - $path = ''; - } - return $path; -} - -sub checked_file { - my $path = shift; - if ( ( defined($path) ) && ( $path ne '' ) ) { - $path =~ s/[\/\\]/$pathslash/go; - } else { - $path = ''; - } - return $path; -} - -sub CheckPath { - my ( $Key, $Value ) = @_; - if ( ( $Value =~ /\// ) && ( $Value !~ /\;/ ) ) # no multipath test yet - { - $Value = checked_path($Value); - unless ( -d $Value ) { - print " error : $Key set to unknown path $Value\n"; - } - } -} - -# set <variable> to <value> -# for <script> set <variable> to <value> -# except for <script> set <variable> to <value> - -my $IniPath = ''; - -#D The kpsewhich program is not available in all tex distributions, so -#D we have to locate it before running it (as suggested by Thomas). - -my @paths; - -if ( $ENV{PATH} =~ /\;/ ) { @paths = split( /\;/, $ENV{PATH} ) } -else { @paths = split( /\:/, $ENV{PATH} ) } - -my $kpsewhich = ''; - -sub found_ini_file { - my $suffix = shift ; - #~ $IniPath = $0 ; - #~ $IniPath ~= s/\.pl$//io ; - #~ $IniPath = $InPath . ".'" + $suffix ; - #~ if (-e $IniPath) { - #~ } - # not really needed to check on texmfscripts, better on own path - print " locating ini file : kpsewhiching texexec.$suffix on scripts\n" if $Verbose ; - my $IniPath = `$kpsewhich --format="texmfscripts" -progname=context texexec.$suffix` ; - chomp($IniPath) ; - if ($IniPath eq '') { - print " locating ini file : kpsewhiching texexec.$suffix elsewhere\n" if $Verbose ; - $IniPath = `$kpsewhich --format="other text files" -progname=context texexec.$suffix` ; - chomp($IniPath) ; - } - return $IniPath ; -} - -if ( $IniPath eq '' ) { - foreach (@paths) { - my $p = checked_path($_) . 'kpsewhich'; - if ( ( -e $p ) || ( -e $p . '.exe' ) ) { - $kpsewhich = $p; - # FP: catch spurious error messages here if there $p has - # spaces and $own_quote is not set - $kpsewhich = ($kpsewhich =~ m/^[^\"].* / ? "\"$kpsewhich\"" : "$kpsewhich") ; - $IniPath = found_ini_file("ini"); - unless ( -e $IniPath ) { $IniPath = found_ini_file("rme") } - last; - } - } - if ($Verbose) { - if ( $kpsewhich eq '' ) { - print " locating ini file : kpsewhich not found in path\n"; - } elsif ( $IniPath eq '' ) { - print " locating ini file : not found by kpsewhich\n"; - } else { - if ( $IniPath =~ /rme/oi ) { - print " locating ini file : not found by kpsewhich, using '.rme' file\n"; - } else { - print " locating ini file : found by kpsewhich\n"; - } - } - } -} - -#D Now, when we didn't find the \type {kpsewhich}, we have -#D to revert to some other method. We could have said: -#D -#D \starttypen -#D unless ($IniPath) -#D { $IniPath = `perl texpath.pl texexec.ini` } -#D \stoptypen -#D -#D But loading perl (for the second time) take some time. Instead of -#D providing a module, which can introduce problems with loading, I -#D decided to copy the code of \type {texpath} into this file. - -use File::Find; -# use File::Copy ; no standard in perl - -my ( $ReportPath, $ReportName, $ReportFile ) = ( 0, 0, 1 ); -my ( $FileToLocate, $PathToStartOn ) = ( '', '' ); -my ( $LocatedPath, $LocatedName, $LocatedFile ) = ( '', '', '' ); - -sub DoLocateFile { # we have to keep on pruning - if ( lc $_ eq $FileToLocate ) { - $LocatedPath = $File::Find::dir; - $LocatedName = $_; - $LocatedFile = $File::Find::name; - } - if ($LocatedName) { $File::Find::prune = 1 } -} - -sub LocatedFile { - $PathToStartOn = shift; - $FileToLocate = lc shift; - if ( $FileToLocate eq '' ) { - $FileToLocate = $PathToStartOn; - $PathToStartOn = $own_path; - } - ( $LocatedPath, $LocatedName, $LocatedFile ) = ( '', '', '' ); - if ( $FileToLocate ne '' ) { - if ( -e $cur_path . $FileToLocate ) { - $LocatedPath = $cur_path; - $LocatedName = $FileToLocate; - $LocatedFile = $cur_path . $FileToLocate; - } else { - $_ = checked_path($PathToStartOn); - if ( -e $_ . $FileToLocate ) { - $LocatedPath = $_; - $LocatedName = $FileToLocate; - $LocatedFile = $_ . $FileToLocate; - } else { - $_ = checked_path($PathToStartOn); - if (/(.*?[\/\\]texmf[\/\\]).*/i) { - my $SavedRoot = $1; - File::Find::find( \&DoLocateFile, - checked_path( $1 . 'context/' ) ); - unless ($LocatedFile) { - File::Find::find( \&DoLocateFile, $SavedRoot ); - } - } else { - $_ = checked_path($_); - File::Find::find( \&DoLocateFile, $_ ); - } - } - } - } - return ( $LocatedPath, $LocatedName, $LocatedFile ); -} - -#D So now we can say: - -unless ($IniPath) { - ( $LocatedPath, $LocatedName, $IniPath ) = - LocatedFile( $own_path, 'texexec.ini' ); - if ($Verbose) { - if ( $IniPath eq '' ) { - print " locating ini file : not found by searching\n"; - } else { - print " locating ini file : found by searching\n"; - } - } -} - -#D The last resorts: - -unless ($IniPath) { - if ( $ENV{TEXEXEC_INI_FILE} ) { - $IniPath = checked_path( $ENV{TEXEXEC_INI_FILE} ) . 'texexec.ini'; - unless ( -e $IniPath ) { $IniPath = '' } - } - if ($Verbose) { - if ( $IniPath eq '' ) { - print " locating ini file : no environment variable set\n"; - } else { - print " locating ini file : found by environment variable\n"; - } - } -} - -unless ($IniPath) { - $IniPath = $own_path . 'texexec.ini'; - unless ( -e $IniPath ) { $IniPath = '' } - if ($Verbose) { - if ( $IniPath eq '' ) { - print " locating ini file : not found in own path\n"; - } else { - print " locating ini file : found in own path\n"; - } - } -} - -#D Now we're ready for loading the initialization file! We -#D also define some non strict variables. Using \type {$Done} -#D permits assignments. - -my %Done; - -unless ($IniPath) { $IniPath = 'texexec.ini' } - -if ( open( INI, $IniPath ) ) { - if ($Verbose) { print " reading : $IniPath\n" } - while (<INI>) { - if ( !/^[a-zA-Z\s]/oi ) { } - elsif (/except for\s+(\S+)\s+set\s+(\S+)\s*to\s*(.*)\s*/goi) { - my $one = $1; - my $two = $2; - my $three = $3; - if ( $one ne $Done{"TeXShell"} ) { - $three =~ s/^[\'\"]//o; - $three =~ s/[\'\"]$//o; - $three =~ s/\s*$//o; - if ($Verbose) { - print " setting : '$two' to '$three' except for '$one'\n"; - } - $Done{"$two"} = $three; - CheckPath( $two, $three ); - } - } elsif (/for\s+(\S+)\s+set\s+(\S+)\s*to\s*(.*)\s*/goi) { - my $one = $1; - my $two = $2; - my $three = $3; - $three =~ s/\s*$//o; - if ( $one eq $Done{"TeXShell"} ) { - $three =~ s/^[\'\"]//o; - $three =~ s/[\'\"]$//o; - if ($Verbose) { - print -" setting : '$two' to '$three' for '$one'\n"; - } - $Done{"$two"} = $three; - CheckPath( $two, $three ); - } - } elsif (/set\s+(\S+)\s*to\s*(.*)\s*/goi) { - my $one = $1; - my $two = $2; - unless ( defined( $Done{"$one"} ) ) { - $two =~ s/^[\'\"]//o; - $two =~ s/[\'\"]$//o; - $two =~ s/\s*$//o; - if ($Verbose) { - print - " setting : '$one' to '$two' for 'all'\n"; - } - $Done{"$one"} = $two; - CheckPath( $one, $two ); - } - } - } - close(INI); - if ($Verbose) { print "\n" } -} elsif ($Verbose) { - print - " warning : $IniPath not found, did you read 'texexec.rme'?\n"; - exit 1; -} else { - print - " warning : $IniPath not found, try 'texexec --verbose'\n"; - exit 1; -} - -sub IniValue { - my ( $Key, $Default ) = @_; - if ( defined( $Done{$Key} ) ) { $Default = $Done{$Key} } - if ($Default =~ /^(true|yes|on)$/io) { - $Default = 1 ; - } elsif ($Default =~ /^(false|no|off)$/io) { - $Default = 0 ; - } - if ($Verbose) { print " used setting : $Key = $Default\n" } - return $Default; -} - -my $TeXShell = IniValue( 'TeXShell', '' ); -my $SetupPath = IniValue( 'SetupPath', '' ); -my $UserInterface = IniValue( 'UserInterface', 'en' ); -my $UsedInterfaces = IniValue( 'UsedInterfaces', 'en' ); -my $TeXFontsPath = IniValue( 'TeXFontsPath', '.' ); -my $MpExecutable = IniValue( 'MpExecutable', 'mpost' ); -my $MpToTeXExecutable = IniValue( 'MpToTeXExecutable', 'mpto' ); -my $DviToMpExecutable = IniValue( 'DviToMpExecutable', 'dvitomp' ); -my $TeXProgramPath = IniValue( 'TeXProgramPath', '' ); -my $TeXFormatPath = IniValue( 'TeXFormatPath', '' ); -my $ConTeXtPath = IniValue( 'ConTeXtPath', '' ); -my $TeXScriptsPath = IniValue( 'TeXScriptsPath', '' ); -my $TeXHashExecutable = IniValue( 'TeXHashExecutable', '' ); -my $TeXExecutable = IniValue( 'TeXExecutable', 'tex' ); -my $TeXVirginFlag = IniValue( 'TeXVirginFlag', '-ini' ); -my $TeXBatchFlag = IniValue( 'TeXBatchFlag', '-interaction=batchmode' ); -my $TeXNonStopFlag = IniValue( 'TeXNonStopFlag', '-interaction=nonstopmode' ); -my $MpBatchFlag = IniValue( 'MpBatchFlag', '-interaction=batchmode' ); -my $MpNonStopFlag = IniValue( 'MpNonStopFlag', '-interaction=nonstopmode' ); -my $TeXPassString = IniValue( 'TeXPassString', '' ); -my $TeXFormatFlag = IniValue( 'TeXFormatFlag', '' ); -my $MpFormatFlag = IniValue( 'MpFormatFlag', '' ); -my $MpVirginFlag = IniValue( 'MpVirginFlag', '-ini' ); -my $MpPassString = IniValue( 'MpPassString', '' ); -my $MpFormat = IniValue( 'MpFormat', $MetaFun ); -my $MpFormatPath = IniValue( 'MpFormatPath', $TeXFormatPath ); -my $UseEnginePath = IniValue( 'UseEnginePath', ''); - -if ($TheEnginePath) { $UseEnginePath = 1 } - -# ok, let's force the engine; let's also forget about -# fmtutil, since it does not support $engine subpaths -# we will replace texexec anyway - -$UseEnginePath = 1 ; -$Alone = 1 ; - -my $FmtLanguage = IniValue( 'FmtLanguage', '' ); -my $FmtBodyFont = IniValue( 'FmtBodyFont', '' ); -my $FmtResponse = IniValue( 'FmtResponse', '' ); -my $TcXPath = IniValue( 'TcXPath', '' ); - - -$SetFile = IniValue( 'SetFile', $SetFile ); - -if ( ($Verbose) && ( $kpsewhich ne '' ) ) { - print "\n"; - my $CnfFile = `$kpsewhich -progname=context texmf.cnf`; - chomp($CnfFile); - print " applications will use : $CnfFile\n"; -} - -if ( ($FmtLanguage) && ( $MainLanguage eq 'standard' ) ) { - $MainLanguage = $FmtLanguage; -} -if ( ($FmtBodyFont) && ( $MainBodyFont eq 'standard' ) ) { - $MainBodyFont = $FmtBodyFont; -} -if ( ($FmtResponse) && ( $MainResponse eq 'standard' ) ) { - $MainResponse = $FmtResponse; -} - -# new versions, > 2004 will have -fmt as switch - -if ( $TeXFormatFlag eq "" ) { - if ($TeXProgram =~ /(etex|pdfetex)/) { - $TeXFormatFlag = "-efmt=" ; # >=2004 -fmt= - } elsif ($TeXProgram =~ /(eomega)/) { - $TeXFormatFlag = "-eoft=" ; # >=2004 obsolete - } elsif ($TeXProgram =~ /(aleph)/) { - $TeXFormatFlag = "-fmt=" ; - } else { - $TeXFormatFlag = "-fmt=" ; - } -} - -if ( $MpFormatFlag eq "" ) { - $MpFormatFlag = "-mem=" ; -} - -if ($TeXProgram) { $TeXExecutable = $TeXProgram } - -my $fmtutil = ''; - -# obsolete -# -# if ( $MakeFormats || $Verbose ) { -# if ($Alone || $UseEnginePath) { -# if ($Verbose) { print " generating format : not using fmtutil\n" } -# } elsif ( $TeXShell =~ /tetex|fptex/i ) { -# foreach (@paths) { -# my $p = checked_path($_) . 'fmtutil'; -# if ( -e $p ) { $fmtutil = $p; last } -# elsif ( -e $p . '.exe' ) { $fmtutil = $p . '.exe'; last } -# } -# $fmtutil = ($fmtutil =~ m/^[^\"].* / ? "\"$fmtutil\"" : "$fmtutil") ; -# if ($Verbose) { -# if ( $fmtutil eq '' ) { -# print " locating fmtutil : not found in path\n"; -# } else { -# print " locating fmtutil : $fmtutil\n"; -# } -# } -# } -# } - -if ($Verbose) { print "\n" } - -unless ($TeXScriptsPath) { $TeXScriptsPath = $own_path } - -unless ($ConTeXtPath) { $ConTeXtPath = $TeXScriptsPath } - -if ( $ENV{"HOME"} ) { - if ($SetupPath) { $SetupPath .= "," } -# my $home = $ENV{"HOME"}; -# $home = ($home =~ m/^[^\"].* / ? "\"$home\"" : "$home") ; -# $SetupPath .= $home; - $SetupPath .= $ENV{"HOME"}; -} - -if ($TeXFormatPath) { $TeXFormatPath =~ s/[\/\\]$//; $TeXFormatPath .= '/' } -if ($MpFormatPath) { $MpFormatPath =~ s/[\/\\]$//; $MpFormatPath .= '/' } -if ($ConTeXtPath) { $ConTeXtPath =~ s/[\/\\]$//; $ConTeXtPath .= '/' } -if ($SetupPath) { $SetupPath =~ s/[\/\\]$//; $SetupPath .= '/' } -if ($TeXScriptsPath) { $TeXScriptsPath =~ s/[\/\\]$//; $TeXScriptsPath .= '/' } - -sub QuotePath { - my ($path) = @_; - my @l = split(",", $path); - map { my $e = $_; $e = ($e =~ m/^[^\"].* / ? "\"$e\"" : "$e"); $_ = $e ;} @l; - return join(",", @l); -} - -$SetupPath = &QuotePath($SetupPath); - -$SetupPath =~ s/\\/\//go; - -my %OutputFormats; - -# the mother of all drivers - -$OutputFormats{dvips} = "dvips"; - -# needs an update - -$OutputFormats{acrobat} = "acrobat"; - -# the core drivers - -$OutputFormats{pdftex} = "pdftex"; $OutputFormats{pdf} = "pdftex"; -$OutputFormats{dvipdfm} = "dvipdfm"; $OutputFormats{dpm} = "dvipdfm"; -$OutputFormats{dvipdfmx} = "dvipdfmx"; $OutputFormats{dpx} = "dvipdfmx"; -$OutputFormats{xetex} = "xetex"; $OutputFormats{xtx} = "xetex"; -$OutputFormats{dvips} = "dvips"; $OutputFormats{ps} = "dvips"; - -# kind of obsolete now that yandy is gone - -$OutputFormats{dvipsone} = "dvipsone"; -$OutputFormats{dviwindo} = "dviwindo"; - -# it was never finished - -$OutputFormats{dviview} = "dviview"; - -my @ConTeXtFormats = ( "nl", "en", "de", "fr", "cz", "uk", "it", "ro", "xx"); - -sub SetInterfaces { - my ( $short, $long, $full ) = @_; - $ConTeXtInterfaces{$short} = $short; - $ConTeXtInterfaces{$long} = $short; - $ResponseInterface{$short} = $full; - $ResponseInterface{$long} = $full; -} - -#SetInterfaces ( "en" , "unknown" , "english" ) ; - -SetInterfaces( "nl", "dutch", "dutch" ); -SetInterfaces( "en", "english", "english" ); -SetInterfaces( "de", "german", "german" ); -SetInterfaces( "fr", "french", "french" ); -SetInterfaces( "cz", "czech", "czech" ); -SetInterfaces( "uk", "british", "english" ); -SetInterfaces( "it", "italian", "italian" ); -SetInterfaces( "no", "norwegian", "norwegian" ); -SetInterfaces( "ro", "romanian", "romanian" ); - -# Sub-option - -struct Subopt => { - desc => '$', # description - vals => '%' # assignable values -}; - -# Main option - -struct Opt => { - desc => '$', # desciption - vals => '%', # assignable values - subs => '%' # suboptions -}; - -my $helpdone = 0; - -sub print_subopt { - my ( $k, $opt ) = @_; - $~ = 'H3'; - write; - for $k ( sort keys %{ $opt->vals } ) { - print_val( $k, ${ $opt->vals }{$k} ); - } - format H3 = -@>>>>>>>>>>>>>>>>>>>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< -"--$k",$opt->desc -. -} - -sub print_val { - my ( $k, $opt ) = @_; - $~ = 'H2'; - write; - format H2 = - @<<<<<<<< : @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< -$k,$opt -. -} - -# read all options - -my $recurse = -1 ; -my $shorthelp; -my @help; -my @opts = <DATA>; -while (@opts) { - $_ = shift @opts; - last if /^--+/; - my ( $k, $v ) = split( /\s+/, $_, 2 ); # was \t - $Help{$k} = read_options($v); -} - -# read a main option plus its -# description, -# assignable values and -# sub-options and their -# description and -# assignable values - -sub read_options { - $recurse++; - my $v = shift; - chomp; - my $opt = $recurse ? Subopt->new() : Opt->new(); - $opt->desc($v); - - while (@opts) { - $_ = shift @opts; - if (/^--+/) { unshift @opts, $_ if $recurse; last } - if ( $recurse && !/^=/ ) { unshift @opts, $_; last } - chomp; - my ( $kk, $vv ) = split( /\s+/, $_, 2 ); # was \t - $vv ||= ''; - if (/^=/) { $opt->vals( $kk, $vv ) } - elsif ( !$recurse ) { $opt->subs( $kk, read_options($vv) ) } - } - $recurse--; - $opt; -} - -sub print_opt { - my ( $k, $opt ) = @_; - if ($helpdone) { $shorthelp or print "\n" } - $helpdone = 1; # hh - $~ = 'H1'; - write; - return if $shorthelp < 0; - for $k ( sort keys %{ $opt->vals } ) { - print_val( $k, ${ $opt->vals }{$k} ); - } - return if $shorthelp > 0; - - for $k ( sort keys %{ $opt->subs } ) { - print_subopt( $k, ${ $opt->subs }{$k} ); - } - format H1 = -@>>>>>>>>>>>>>>>>>>>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< -"--$k",$opt->desc -. -} - -# help to help - -sub show_help_options { - print # "\n" . - " --help overview of all options and their values\n" - . " --help all all about all options\n" - . " --help short just the main options\n" - . " --help mode ... pdf all about a few options\n" - . " --help '*.pdf' all about options containing 'pdf'\n" - . "\n" - . " more info http://www.pragma-ade.com/general/manuals/mtexexec.pdf\n" - . " http://www.ntg.nl/mailman/listinfo/ntg-context\n"; -} - -# determine what user wants to see - -if ($HelpAsked) { - $shorthelp = 0; - @help = ( sort keys %Help ); - if ( "@ARGV" eq "all" ) { # everything - } elsif ( "@ARGV" eq "short" ) { # nearly everything - $shorthelp--; - } elsif ( "@ARGV" eq "help" ) { # help on help - show_help_options; - exit; - } elsif (@ARGV) { # one or a few options, completely - my @h = @ARGV; - @help = (); - for (@h) { # print "testing $_\n"; - # next if (/^[\*\?]/) ; # HH, else error - if (/^[\*\?]/) { $_ = ".$_" } # HH, else error - $Help{$_} and push( @help, $_ ) or do { - my $unknown = $_; - for ( keys %Help ) { /$unknown/ and push( @help, $_ ) } - } - } - } else { # all main option and their assignable values - $shorthelp++; - } -} - -sub show_help_info { - map { print_opt( $_, $Help{$_} ) } @help; -} - -# uncomment this to see the structure of a Help element: -# print Dumper($Help{pdfselect}); - -#### end of help system - -my $FinalRunNeeded = 0; - -sub MPJobName { - my $JobName = shift; - my $MPfile = shift; - my $MPJobName = ''; - if ( -e "$JobName-$MPfile.mp" && -s "$JobName-$MPfile.mp" > 100 ) { - $MPJobName = "$JobName-$MPfile.mp" - } elsif ( -e "$MPfile.mp" && -s "$MPfile.mp" > 100 ) { - $MPJobName = "$MPfile.mp" - } else { $MPJobName = "" } - return $MPJobName; -} - -sub System { - my $cmd = shift ; - unless ( $dosish && ! $escapeshell ) { - $cmd =~ s/([^\\])\&/$1\\\&/io ; - } - if ($Verbose) { - print "\n$cmd\n\n" ; - } - system($cmd) -} - -sub Pipe { - my $cmd = shift ; - unless ( $dosish && ! $escapeshell ) { - $cmd =~ s/([^\\])\&/$1\\\&/io ; - } - if ($Verbose) { - print "\n$cmd\n\n" ; - } - return `$cmd` -} - - -sub RunPerlScript { - my ( $ScriptName, $Options ) = @_; - my $cmd = ''; - $own_quote = ($own_path =~ m/^[^\"].* / ? "\"" : "") ; - if ($Verbose) { - $Options .= ' --verbose' ; - } - if ($dosish) { - if ( -e "own_path$ScriptName$own_type" ) { - $cmd = -"$own_stub$own_quote$own_path$ScriptName$own_type$own_quote $Options"; - } elsif ( -e "$TeXScriptsPath$ScriptName$own_type" ) { - $cmd = -"$own_stub$own_quote$TeXScriptsPath$ScriptName$own_type$own_quote $Options"; - } else { - $cmd = ""; - } - } else { - $cmd = "$ScriptName $Options"; - } - unless ( $cmd eq "" ) { - System($cmd) ; - } -} - -my $FullFormat = ''; - -sub CheckOutputFormat { - my $Ok = 1; - if ( $OutputFormat ne 'standard' ) { - my @OutputFormat = split( /,/, $OutputFormat ); - foreach my $F (@OutputFormat) { - if ( defined( $OutputFormats{ lc $F } ) ) { - my $OF = $OutputFormats{ lc $F }; - next if ( ",$FullFormat," =~ /\,$OF\,/ ); - if ($FullFormat) { $FullFormat .= "," } - $FullFormat .= "$OutputFormats{lc $F}"; - } else { - $Ok = 0; - } - } - if ( !$Ok ) { - print(" unknown output format : $OutputFormat\n"); - } - } - unless ($FullFormat) { $FullFormat = $OutputFormat } -} # 'standard' to terminal - -sub MakeOptionFile { - my ( $FinalRun, $FastDisabled, $JobName, $JobSuffix, $KindOfRun ) = @_; - open( OPT, ">$JobName.top" ); - print OPT "\% $JobName.top\n"; - print OPT "\\unprotect\n"; - if ($EnterBatchMode) { print OPT "\\batchmode\n" } - if ($EnterNonStopMode) { print OPT "\\nonstopmode\n" } - if ($Paranoid) { - print " paranoid file mode : very true\n"; - print OPT "\\def\\maxreadlevel{1}\n" ; - } - $ModeFile =~ s/\\/\//gio ; # do this at top of file - $Result =~ s/\\/\//gio ; # do this at top of file - if ( $ModeFile ne '' ) { print OPT "\\readlocfile{$ModeFile}{}{}" } - if ( $Result ne '' ) { print OPT "\\setupsystem[file=$Result]\n" } - elsif ($Suffix) { print OPT "\\setupsystem[file=$JobName$Suffix]\n" } - if ( $InpPath ne "" ) { - $InpPath =~ s/\\/\//go; - $InpPath =~ s/\/$//go; - print OPT "\\usepath[$InpPath]\n"; - } - $MainLanguage = lc $MainLanguage; - unless ( $MainLanguage eq "standard" ) { - print OPT "\\setuplanguage[$MainLanguage]\n"; - } - # can best become : \use...[mik] / [web] - if ( $TeXShell =~ /MikTeX/io ) { - print OPT "\\def\\MPOSTbatchswitch \{$MpBatchFlag\}"; - print OPT "\\def\\MPOSTnonstopswitch \{$MpNonStopFlag\}"; - print OPT "\\def\\MPOSTformatswitch \{$MpPassString $MpFormatFlag\}"; - } - # - if ( $FullFormat ne 'standard' ) { - print OPT "\\setupoutput[$FullFormat]\n"; - } - if ($UseColor) { print OPT "\\setupcolors[\\c!state=\\v!start]\n" } - if ( $NoMPMode || $NoMPRun || $AutoMPRun ) { - print OPT "\\runMPgraphicsfalse\n"; - } - if ( ($FastMode) && ( !$FastDisabled ) ) { print OPT "\\fastmode\n" } - if ($SilentMode) { print OPT "\\silentmode\n" } - if ( $Separation ne "" ) { - print OPT "\\setupcolors[\\c!split=$Separation]\n"; - } - if ($SetupPath) { print OPT "\\setupsystem[\\c!directory=\{$SetupPath\}]\n" } - if ($dosish) { - print OPT "\\setupsystem[\\c!type=mswin]\n" - } else { # no darwin handling in old texexec - print OPT "\\setupsystem[\\c!type=unix]\n" - } - print OPT "\\setupsystem[\\c!n=$KindOfRun]\n"; - $_ = $PaperFormat; - #unless (($PdfArrange)||($PdfSelect)||($PdfCombine)||($PdfCopy)) - unless ( ($PdfSelect) || ($PdfCombine) || ($PdfCopy) || ($PdfTrim) ) { - if (/.4.3/goi) { - print OPT "\\setuppapersize[A4][A3]\n" ; - } elsif (/.5.4/goi) { - print OPT "\\setuppapersize[A5][A4]\n" ; - } elsif ( !/standard/ ) { - s/x/\*/io; - if (/\w+\d+/) { $_ = uc $_ } - my ( $from, $to ) = split(/\*/); - if ( $to eq "" ) { $to = $from } - print OPT "\\setuppapersize[$from][$to]\n"; - } - } - if ( ( $PdfSelect || $PdfCombine || $PdfCopy || $PdfTrim || $PdfArrange ) - && ( $Background ne '' ) ) - { - print " background graphic : $Background\n"; - print OPT "\\defineoverlay[whatever][{\\externalfigure[$Background][\\c!factor=\\v!max]}]\n"; - print OPT "\\setupbackgrounds[\\v!page][\\c!background=whatever]\n"; - } - if ($CenterPage) { - print OPT - "\\setuplayout[\\c!location=\\v!middle,\\c!marking=\\v!on]\n"; - } - if ($NoMapFiles) { - print OPT "\\disablemapfiles\n"; - } - if ($NoArrange) { print OPT "\\setuparranging[\\v!disable]\n" } - elsif ( $Arrange || $PdfArrange ) { - $FinalRunNeeded = 1; - if ($FinalRun) { - my $DupStr; - if ($NoDuplex) { $DupStr = "" } - else { $DupStr = ",\\v!doublesided" } - if ( $PrintFormat eq '' ) { - print OPT "\\setuparranging[\\v!normal]\n"; - } elsif ( $PrintFormat =~ /.*up/goi ) { - print OPT "\\setuparranging[2UP,\\v!rotated$DupStr]\n"; - } elsif ( $PrintFormat =~ /.*down/goi ) { - print OPT "\\setuparranging[2DOWN,\\v!rotated$DupStr]\n"; - } elsif ( $PrintFormat =~ /.*side/goi ) { - print OPT "\\setuparranging[2SIDE,\\v!rotated$DupStr]\n"; - } else { - print OPT "\\setuparranging[$PrintFormat]\n"; - } - } else { - print OPT "\\setuparranging[\\v!disable]\n"; - } - } - if ($Arguments) { print OPT "\\setupenv[$Arguments]\n" } - if ($Input) { print OPT "\\setupsystem[inputfile=$Input]\n" } - else { print OPT "\\setupsystem[inputfile=$JobName.$JobSuffix]\n" } - if ($Random) { print OPT "\\setupsystem[\\c!random=$RandomSeed]\n" } - if ($Mode) { print OPT "\\enablemode[$Mode]\n" } - if ($Pages) { - if ( lc $Pages eq "odd" ) { - print OPT "\\chardef\\whichpagetoshipout=1\n"; - } elsif ( lc $Pages eq "even" ) { - print OPT "\\chardef\\whichpagetoshipout=2\n"; - } else { - my @Pages = split( /\,/, $Pages ); - $Pages = ''; - foreach my $page (@Pages) { - if ( $page =~ /\:/ ) { - my ( $from, $to ) = split( /\:/, $page ); - foreach ( my $i = $from ; $i <= $to ; $i++ ) { - $Pages .= $i . ','; - } - } else { - $Pages .= $page . ','; - } - } - chop $Pages; - print OPT "\\def\\pagestoshipout\{$Pages\}\n"; - } - } - print OPT "\\protect\n"; - if ( $Filters ne "" ) { - foreach my $F ( split( /,/, $Filters ) ) { - print OPT "\\useXMLfilter[$F]\n"; - } - } - if ( $Modules ne "" ) { - foreach my $M ( split( /,/, $Modules ) ) { - print OPT "\\usemodule[$M]\n"; - } - } - if ( $Environments ne "" ) { - foreach my $E ( split( /,/, $Environments ) ) { - print OPT "\\environment $E\n"; - } - } - close(OPT); -} - -my $UserFileOk = 0; -my @MainLanguages; -my $AllLanguages = ''; - -sub MakeUserFile { - $UserFileOk = 0; - if ($AllPatterns) { - open( USR, ">cont-fmt.tex" ); - print USR "\\preloadallpatterns\n"; - } else { - return - if ( ( $MainLanguage eq 'standard' ) - && ( $MainBodyFont eq 'standard' ) ); - print " preparing user file : cont-fmt.tex\n"; - open( USR, ">cont-fmt.tex" ); - print USR "\\unprotect\n"; - $AllLanguages = $MainLanguage; - if ( $MainLanguage ne 'standard' ) { - @MainLanguages = split( /\,/, $MainLanguage ); - foreach (@MainLanguages) { - print USR "\\installlanguage[\\s!$_][\\c!state=\\v!start]\n"; - } - $MainLanguage = $MainLanguages[0]; - print USR "\\setupcurrentlanguage[\\s!$MainLanguage]\n"; - } - if ( $MainBodyFont ne 'standard' ) { - print USR "\\definetypescriptsynonym[cmr][$MainBodyFont]"; - print USR "\\definefilesynonym[font-cmr][font-$MainBodyFont]\n"; - } - print USR "\\protect\n"; - } - print USR "\\endinput\n"; - close(USR); - ReportUserFile(); - print "\n"; - $UserFileOk = 1; -} - -sub RemoveResponseFile { unlink "mult-def.tex" } - -sub MakeResponseFile { - if ( $MainResponse eq 'standard' ) { RemoveResponseFile() } - elsif ( !defined( $ResponseInterface{$MainResponse} ) ) { - RemoveResponseFile(); - } else { - my $MR = $ResponseInterface{$MainResponse}; - print " preparing interface file : mult-def.tex\n"; - print " response language : $MR\n"; - open( DEF, ">mult-def.tex" ); - print DEF "\\def\\currentresponses\{$MR\}\n\\endinput\n"; - close(DEF); - } -} - -sub RestoreUserFile { - unlink "cont-fmt.log"; - rename "cont-fmt.tex", "cont-fmt.log"; - ReportUserFile(); -} - -sub ReportUserFile { - return unless ($UserFileOk); - print "\n"; - if ( $MainLanguage ne 'standard' ) { - print " additional patterns : $AllLanguages\n"; - print " default language : $MainLanguage\n"; - } - if ( $MainBodyFont ne 'standard' ) { - print " default bodyfont : $MainBodyFont\n"; - } -} - -sub CheckPositions { } - -my $ConTeXtVersion = "unknown"; -my $ConTeXtModes = ''; - -sub ScanTeXPreamble { - my ($FileName) = @_; - open( TEX, $FileName ); - while (<TEX>) { - chomp; - if (/^\%.*/) { - if (/tex=([a-z]*)/goi) { $TeXExecutable = $1 } - if (/translat.*?=([\:\/0-9\-a-z]*)/goi) { $TeXTranslation = $1 } - if (/program=([a-z]*)/goi) { $TeXExecutable = $1 } - if (/output=([a-z\,\-]*)/goi) { $OutputFormat = $1 } - if (/modes=([a-z\,\-]*)/goi) { $ConTeXtModes = $1 } - if (/textree=([a-z\-]*)/goi) { $TeXTree = $1 } - if (/texroot=([a-z\-]*)/goi) { $TeXRoot = $1 } - if ( $ConTeXtInterface eq "unknown" ) { - - if (/format=([a-z]*)/goi) { - $ConTeXtInterface = $ConTeXtInterfaces{$1}; - } - if (/interface=([a-z]*)/goi) { - $ConTeXtInterface = $ConTeXtInterfaces{"$1"}; - } - } - if (/version=([a-z]*)/goi) { $ConTeXtVersion = $1 } - } else { - last; - } - } - close(TEX); - - # handy later on - - $ProducePdfT = ($OutputFormat eq "pdftex") ; - $ProducePdfM = ($OutputFormat eq "dvipdfm") ; - $ProducePdfX = ($OutputFormat eq "dvipdfmx") ; - $ProducePdfXTX = ($OutputFormat eq "xetex") ; - $ProducePs = ($OutputFormat eq "dvips") ; -} - -sub ScanContent { - my ($ConTeXtInput) = @_; - open( TEX, $ConTeXtInput ); - while (<TEX>) { - next if (/^\%/) ; - if ( -/\\(starttekst|stoptekst|startonderdeel|startdocument|startoverzicht)/ - ) - { - $ConTeXtInterface = "nl"; - last; - } elsif (/\\(stelle|verwende|umgebung|benutze)/) { - $ConTeXtInterface = "de"; - last; - } elsif (/\\(stel|gebruik|omgeving)/) { - $ConTeXtInterface = "nl"; - last; - } elsif (/\\(use|setup|environment)/) { - $ConTeXtInterface = "en"; - last; - } elsif (/\\(usa|imposta|ambiente)/) { - $ConTeXtInterface = "it"; - last; - } elsif (/(height|width|style)=/) { - $ConTeXtInterface = "en"; - last; - } elsif (/(hoehe|breite|schrift)=/) { - $ConTeXtInterface = "de"; - last; - } - # brr, can be \c! - elsif (/(hoogte|breedte|letter)=/) { $ConTeXtInterface = "nl"; last } - elsif (/(altezza|ampiezza|stile)=/) { $ConTeXtInterface = "it"; last } - elsif (/externfiguur/) { $ConTeXtInterface = "nl"; last } - elsif (/externalfigure/) { $ConTeXtInterface = "en"; last } - elsif (/externeabbildung/) { $ConTeXtInterface = "de"; last } - elsif (/figuraesterna/) { $ConTeXtInterface = "it"; last } - } - close(TEX); -} - -if ( $ConTeXtInterfaces{$ConTeXtInterface} ) { - $ConTeXtInterface = $ConTeXtInterfaces{$ConTeXtInterface}; -} - -my $Problems = my $Ok = 0; - -sub PrepRunTeX { - my ( $JobName, $JobSuffix, $PipeString ) = @_; - my $cmd; - my $TeXProgNameFlag = ''; - if ( !$dosish ) # we assume tetex on linux - { - $TeXProgramPath = ''; - $TeXFormatPath = ''; - if ( !$TeXProgNameFlag - && ( $Format =~ /^cont/ ) - && ( $TeXPassString !~ /progname/io ) ) - { - $TeXProgNameFlag = "-progname=context"; - } - } - $own_quote = ($TeXProgramPath =~ m/^[^\"].* / ? "\"" : "") ; - $cmd = join( ' ', - "$own_quote$TeXProgramPath$TeXExecutable$own_quote", - $TeXProgNameFlag, $TeXPassString, $PassOn, "" ); - if ($EnterBatchMode) { $cmd .= "$TeXBatchFlag " } - if ($EnterNonStopMode) { $cmd .= "$TeXNonStopFlag " } - if ( $TeXTranslation ne '' ) { $cmd .= "-translate-file=$TeXTranslation " } - $cmd .= "$TeXFormatFlag$TeXFormatPath$Format $JobName.$JobSuffix $PipeString"; - return $cmd; -} - -my $emergencyend = "" ; -#~ my $emergencyend = "\\emergencyend" ; - -sub RunTeX { - my ( $JobName, $JobSuffix ) = @_; - my $StartTime = time; - my $cmd = PrepRunTeX($JobName, $JobSuffix, ''); - if ($EnterBatchMode) { - $Problems = System("$cmd $emergencyend"); - } else { - $Problems = System("$cmd $emergencyend"); - } - my $StopTime = time - $StartTime; - print "\n return code : $Problems"; - print "\n run time : $StopTime seconds\n"; - return $Problems; -} - -sub PushResult { - my $File = shift; - $File =~ s/\..*$//o; - $Result =~ s/\..*$//o; - if ( ( $Result ne '' ) && ( $Result ne $File ) ) { - print " outputfile : $Result\n"; - unlink "texexec.tuo"; - rename "$File.tuo", "texexec.tuo"; - unlink "texexec.log"; - rename "$File.log", "texexec.log"; - unlink "texexec.dvi"; - rename "$File.dvi", "texexec.dvi"; - unlink "texexec.pdf"; - rename "$File.pdf", "texexec.pdf"; - - if ( -e "$Result.tuo" ) { - unlink "$File.tuo"; - rename "$Result.tuo", "$File.tuo"; - } - } - if ($Optimize) { unlink "$File.tuo" } -} - -sub PopResult { - my $File = shift; - $File =~ s/\..*$//o; - $Result =~ s/\..*$//o; - if ( ( $Result ne '' ) && ( $Result ne $File ) ) { - print " renaming : $File to $Result\n"; - unlink "$Result.tuo"; - rename "$File.tuo", "$Result.tuo"; - unlink "$Result.log"; - rename "$File.log", "$Result.log"; - unlink "$Result.dvi"; - rename "$File.dvi", "$Result.dvi"; - if ( -e "$File.dvi" ) { CopyFile( "$File.dvi", "$Result.dvi" ) } - unlink "$Result.pdf"; - rename "$File.pdf", "$Result.pdf"; - if ( -e "$File.pdf" ) { CopyFile( "$File.pdf", "$Result.pdf" ) } - return if ( $File ne "texexec" ); - rename "texexec.tuo", "$File.tuo"; - rename "texexec.log", "$File.log"; - rename "texexec.dvi", "$File.dvi"; - rename "texexec.pdf", "$File.pdf"; - } -} - -sub RunTeXutil { - my $StopRunning; - my $JobName = shift; - unlink "$JobName.tup"; - rename "$JobName.tuo", "$JobName.tup"; - print " sorting and checking : running texutil\n"; - my $TcXSwitch = ''; - if ( $TcXPath ne '' ) { $TcXSwitch = "--tcxpath=$TcXPath" } - RunPerlScript( $TeXUtil, "--ref --ij --high $TcXPath $JobName" ); - - if ( -e "$JobName.tuo" ) { - CheckPositions($JobName); - #~ print " utility file check : $JobName.tup <-> $JobName.tuo\n"; - $StopRunning = !compare( "$JobName.tup", "$JobName.tuo" ); - } else { - $StopRunning = 1; - } # otherwise potential loop - if ( !$StopRunning ) { - print "\n utility file analysis : another run needed\n"; - } - return $StopRunning; -} - -sub PurgeFiles { - my $JobName = shift; - print "\n purging files : $JobName\n"; - RunPerlScript( $TeXUtil, "--purge $JobName" ); - unlink( $Result . '.log' ) if ( -f $Result . '.log' ); -} - -sub RunTeXMP { - my $JobName = shift; - my $MPfile = shift; - my $MPrundone = 0; - my $MPJobName = MPJobName( $JobName, $MPfile ); - my $MPFoundJobName = ""; - if ( $MPJobName ne "" ) { - if ( open( MP, "$MPJobName" ) ) { - $_ = <MP>; - chomp; # we should handle the prefix as well - if (/^\%\s+translate.*?\=([\w\d\-]+)/io) { $TeXTranslation = $1 } - if (/collected graphics of job \"(.+)\"/i) { $MPFoundJobName = $1 } - close(MP); - if ( $MPFoundJobName ne "" ) { - if ( $JobName =~ /$MPFoundJobName$/i ) { - if ( $MpExecutable ne '' ) { - print - " generating graphics : metaposting $MPJobName\n"; - my $ForceMpy = ""; - if ($MpyForce) { $ForceMpy = "--mpyforce" } - my $ForceTCX = ''; - if ( $TeXTranslation ne '' ) { - $ForceTCX = "--translate=$TeXTranslation "; - } - if ($EnterBatchMode) { - RunPerlScript( $TeXExec, -"$ForceTCX $ForceMpy --mptex --nomp --batch $MPJobName" - ); - } elsif ($EnterNonStopMode) { - RunPerlScript( $TeXExec, -"$ForceTCX $ForceMpy --mptex --nomp --nonstop $MPJobName" - ); - } else { - RunPerlScript( $TeXExec, - "$ForceTCX $ForceMpy --mptex --nomp $MPJobName" - ); - } - } else { - print - " generating graphics : metapost cannot be run\n"; - } - $MPrundone = 1; - } - } - } - } - return $MPrundone; -} - -sub CopyFile { # agressive copy, works for open files like in gs - my ( $From, $To ) = @_; - return unless open( INP, "<$From" ); - binmode INP; - return unless open( OUT, ">$To" ); - binmode OUT; - while (<INP>) { print OUT $_ } - close(INP); - close(OUT); -} - -#~ sub CheckMPChanges { - #~ my $JobName = shift; - #~ my $checksum = 0; - #~ my $MPJobName = MPJobName( $JobName, "mpgraph" ); - #~ if ( open( MP, $MPJobName ) ) { - #~ while (<MP>) { - #~ unless (/random/oi) { - #~ $checksum += do { unpack( "%32C*", <MP> ) % 65535 } - #~ } - #~ } - #~ close(MP); - #~ } - #~ $MPJobName = MPJobName( $JobName, "mprun" ); - #~ if ( open( MP, $MPJobName ) ) { - #~ while (<MP>) { - #~ unless (/random/oi) { - #~ $checksum += do { unpack( "%32C*", <MP> ) % 65535 } - #~ } - #~ } - #~ close(MP); - #~ } - #~ print " mpgraph/mprun : $checksum\n"; - #~ return $checksum; -#~ } - -sub CheckMPChanges { - my $JobName = shift; my $str = '' ; - my $MPJobName = MPJobName( $JobName, "mpgraph" ); - if ( open( MP, $MPJobName ) ) { - $str .= do { local $/ ; <MP> ; } ; - close(MP) ; - } - $MPJobName = MPJobName( $JobName, "mprun" ); - if ( open( MP, $MPJobName ) ) { - $str .= do { local $/ ; <MP> ; } ; - close(MP) ; - } - $str =~ s/^.*?random.*?$//oim ; - return Digest::MD5::md5_hex($str) ; -} - -#~ sub CheckTubChanges { - #~ my $JobName = shift; - #~ my $checksum = 0; - #~ if ( open( TUB, "$JobName.tub" ) ) { - #~ while (<TUB>) { - #~ $checksum += do { unpack( "%32C*", <TUB> ) % 65535 } - #~ } - #~ close(TUB); - #~ } - #~ return $checksum; -#~ } - -sub CheckTubChanges { - my $JobName = shift; my $str = '' ; - if ( open( TUB, "$JobName.tub" ) ) { - $str = do { local $/ ; <TUB> ; } ; - close(TUB); - } - return Digest::MD5::md5_hex($str); -} - - -my $DummyFile = 0; - -sub isXMLfile { - my $Name = shift; - if ( ($ForceXML) || ( $Name =~ /\.(xml|fo|fox)$/io ) ) { return 1 } - else { - open( XML, $Name ); - my $str = <XML>; - close(XML); - return ( $str =~ /\<\?xml /io ); - } -} - -sub RunConTeXtFile { - my ( $JobName, $JobSuffix ) = @_; - if ($AutoPath) { - if ($JobName =~ /^(.*)[\/\\](.*?)$/o) { - $InpPath = $1 ; - $JobName = $2 ; - } - } - $JobName =~ s/\\/\//goi; - $InpPath =~ s/\\/\//goi; - my $OriSuffix = $JobSuffix; - if ($JobSuffix =~ /\_fo$/i) { - if (! -f $JobName) { - print "stripping funny suffix : _fo\n"; - $JobName =~ s/\_fo$//io ; - $JobSuffix =~ s/\_fo$//io ; - $OriSuffix =~ s/\_fo$//io ; - } - } - if (($dosish) && ($PdfClose)) { - my $ok = System("pdfclose --file $JobName.pdf") if -e "$JobName.pdf" ; - if (($Result ne '') && (-e "$Result.pdf")) { - $ok = System("pdfclose --file $Result.pdf") ; - } - System("pdfclose --all") unless $ok ; - } - if ( -e "$JobName.$JobSuffix" ) { - $DummyFile = ( ($ForceXML) || ( $JobSuffix =~ /(xml|fo|fox)/io ) ); - } - # to be considered : - # { $DummyFile = isXMLfile("$JobName.$JobSuffix") } - elsif ( $InpPath ne "" ) { - my @InpPaths = split( /,/, $InpPath ); - foreach my $rp (@InpPaths) { - if ( -e "$rp/$JobName.$JobSuffix" ) { $DummyFile = 1; last } - } - } - if ($DummyFile) { - open( TMP, ">$JobName.run" ); - if ( ( $JobSuffix =~ /(xml|fo|fox)/io ) || $ForceXML ) { - # scan xml preamble - open(XML,"<$JobName.$JobSuffix") ; - while (<XML>) { - if (/\<\?context\-directive\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*?)\s*\?\>/o) { - my ($class, $key, $value, $rest) = ($1, $2, $3, $4) ; - if ($class eq 'job') { - if (($key eq 'mode') || ($key eq 'modes')) { - print TMP "\\enablemode[$value]\n" ; - } elsif (($key eq 'stylefile') || ($key eq 'environment')) { - print TMP "\\environment $value\n" ; - } elsif ($key eq 'module') { - print TMP "\\usemodule[$value]\n" ; - } elsif ($key eq 'interface') { - $ConTeXtInterface = $value ; - } elsif ($key eq 'control') { - if ($rest == 'purge') { $Purge = 1 } - } - } - } elsif (/\<[a-z]+/io) { - last ; - } - } - close(XML) ; - if ( $Filters ne "" ) { - print " using xml filters : $Filters\n"; - } - print TMP "\\starttext\n"; - print TMP "\\processXMLfilegrouped{$JobName.$JobSuffix}\n"; - print TMP "\\stoptext\n"; - } else { - print TMP "\\starttext\n"; - print TMP "\\processfile{$JobName.$JobSuffix}\n"; - print TMP "\\stoptext\n"; - } - close(TMP); - $JobSuffix = "run"; - } - if ( ( -e "$JobName.$JobSuffix" ) || ($GlobalFile) ) { - unless ($DummyFile) { # we don't need this for xml - ScanTeXPreamble("$JobName.$JobSuffix"); - if ( $ConTeXtInterface eq "unknown" ) { - ScanContent("$JobName.$JobSuffix"); - } - } - if ( $ConTeXtInterface eq "unknown" ) { - $ConTeXtInterface = $UserInterface; - } - if ( $ConTeXtInterface eq "unknown" ) { $ConTeXtInterface = "en" } - if ( $ConTeXtInterface eq "" ) { $ConTeXtInterface = "en" } - CheckOutputFormat; - my $StopRunning = 0; - my $MPrundone = 0; - if ( $Format eq '' ) { $Format = "cont-$ConTeXtInterface" } - print " executable : $TeXProgramPath$TeXExecutable\n"; - print " format : $TeXFormatPath$Format\n"; - if ($InpPath) { print " source path : $InpPath\n" } - - if ($DummyFile) { - print " dummy file : $JobName.$JobSuffix\n"; - } - print " inputfile : $JobName\n"; - print " output : $FullFormat\n"; - print " interface : $ConTeXtInterface\n"; - if ( $TeXTranslation ne '' ) { - print " translation : $TeXTranslation\n"; - } - my $Options = ''; - if ($Random) { $Options .= " random" } - if ($FastMode) { $Options .= " fast" } - if ($FinalMode) { $Options .= " final" } - if ($Verbose) { $Options .= " verbose" } - if ($TypesetListing) { $Options .= " listing" } - if ($TypesetModule) { $Options .= " module" } - if ($TypesetFigures) { $Options .= " figures" } - if ($MakeFormats) { $Options .= " make" } - if ($RunOnce) { $Options .= " once" } - if ($UseColor) { $Options .= " color" } - if ($EnterBatchMode) { $Options .= " batch" } - if ($EnterNonStopMode) { $Options .= " nonstop" } - if ($NoMPMode) { $Options .= " nomp" } - if ($CenterPage) { $Options .= " center" } - if ($Arrange) { $Options .= " arrange" } - if ($NoArrange) { $Options .= " no-arrange" } - if ($Options) { print " options :$Options\n" } - if ($ConTeXtModes) { print " possible modes : $ConTeXtModes\n" } - if ($Mode) { print " current mode : $Mode\n" } - else { print " current mode : none\n" } - if ($Arguments) { print " arguments : $Arguments\n" } - if ($Modules) { print " modules : $Modules\n" } - if ($Environments) { print " environments : $Environments\n" } - if ($Suffix) { $Result = "$JobName$Suffix" } - PushResult($JobName); - $Problems = 0; - my $TeXRuns = 0; - - if ( ($PdfArrange) || ($PdfSelect) || ($RunOnce) ) { - MakeOptionFile( 1, 1, $JobName, $OriSuffix, 3 ); - print "\n"; - $Problems = RunTeX( $JobName, $JobSuffix ); - if ($ForceTeXutil) { $Ok = RunTeXutil($JobName) } - CopyFile( "$JobName.top", "$JobName.tmp" ); - unlink "$JobName.top"; # runtime option file - PopResult($JobName); - } else { - while ( !$StopRunning && ( $TeXRuns < $NOfRuns ) && ( !$Problems ) ) - { - ++$TeXRuns; - if ( $TeXRuns == 1 ) { - MakeOptionFile( 0, 0, $JobName, $OriSuffix, 1 ); - } else { - MakeOptionFile( 0, 0, $JobName, $OriSuffix, 2 ); - } - print " TeX run : $TeXRuns\n\n"; - my ( $mpchecksumbefore, $mpchecksumafter ) = ( '', '' ); - my ( $tubchecksumbefore, $tubchecksumafter ) = ( '', '' ); - if ($AutoMPRun) { $mpchecksumbefore = CheckMPChanges($JobName) } - $tubchecksumbefore = CheckTubChanges($JobName) ; - $Problems = RunTeX( $JobName, $JobSuffix ); - $tubchecksumafter = CheckTubChanges($JobName) ; - if ($AutoMPRun) { $mpchecksumafter = CheckMPChanges($JobName) } - if ( ( !$Problems ) && ( $NOfRuns > 1 ) ) { - unless ( $NoMPMode ) { - $MPrundone = RunTeXMP( $JobName, "mpgraph" ); - $MPrundone = RunTeXMP( $JobName, "mprun" ); - } - $StopRunning = RunTeXutil($JobName); - if ($AutoMPRun) { - $StopRunning = - ( $StopRunning - && ( $mpchecksumafter eq $mpchecksumbefore ) ); - } - $StopRunning = - ( $StopRunning - && ( $tubchecksumafter eq $tubchecksumbefore ) ); - } - } - if ( ( $NOfRuns == 1 ) && $ForceTeXutil ) { - $Ok = RunTeXutil($JobName); - } - if ( ( !$Problems ) - && ( ( $FinalMode || $FinalRunNeeded ) ) - && ( $NOfRuns > 1 ) ) - { - MakeOptionFile( 1, $FinalMode, $JobName, $OriSuffix, 4 ); - print " final TeX run : $TeXRuns\n\n"; - $Problems = RunTeX( $JobName, $JobSuffix ); - } - CopyFile( "$JobName.top", "$JobName.tmp" ); - unlink "$JobName.tup"; # previous tuo file - unlink "$JobName.top"; # runtime option file - if ($ProducePdfX) { - $ENV{'backend'} = $ENV{'progname'} = 'dvipdfm' ; - $ENV{'TEXFONTMAPS'} = '.;$TEXMF/fonts/map/{dvipdfm,dvips,}//' ; - System("dvipdfmx -d 4 $JobName") ; - } elsif ($ProducePdfM) { - $ENV{'backend'} = $ENV{'progname'} = 'dvipdfm' ; - $ENV{'TEXFONTMAPS'} = '.;$TEXMF/fonts/map/{dvipdfm,dvips,}//' ; - System("dvipdfm $JobName") ; - } elsif ($ProducePdfXTX) { - $ENV{'backend'} = $ENV{'progname'} = 'xetex' ; - $ENV{'TEXFONTMAPS'} = '.;$TEXMF/fonts/map/{xetex,pdftex,dvips,}//' ; - System("xdv2pdf $JobName.xdv") ; - } elsif ($ProducePs) { - $ENV{'backend'} = $ENV{'progname'} = 'dvips' ; - $ENV{'TEXFONTMAPS'} = '.;$TEXMF/fonts/map/{dvips,pdftex,}//' ; - # temp hack, some day there will be map file loading in specials - my $mapfiles = '' ; - if (-f "$JobName.tui") { - open(TUI,"$JobName.tui") ; - while (<TUI>) { - if (/c \\usedmapfile\{.\}\{(.*?)\}/o) { - $mapfiles .= "-u +$1 " ; - } - } - close(TUI) ; - } - System("dvips $mapfiles $JobName.dvi") ; - } - PopResult($JobName); - } - if ($Purge) { PurgeFiles($JobName) } - if ($DummyFile) # $JobSuffix == run - { - unlink "$JobName.$JobSuffix"; - } - if ((!$Problems) && ($PdfOpen) && ($PdfOpenCall)) { - if ($Result ne '') { - System("$PdfOpenCall $Result.pdf") if -f "$Result.pdf" - } else { - System("$PdfOpenCall $JobName.pdf") if -f "$JobName.pdf" - } - } - } -} - -sub RunSomeTeXFile { - my ( $JobName, $JobSuffix ) = @_; - if ( -e "$JobName.$JobSuffix" ) { - PushResult($JobName); - print " executable : $TeXProgramPath$TeXExecutable\n"; - print " format : $TeXFormatPath$Format\n"; - print " inputfile : $JobName.$JobSuffix\n"; - $Problems = RunTeX( $JobName, $JobSuffix ); - PopResult($JobName); - } -} - -my $ModuleFile = "texexec"; -my $ListingFile = "texexec"; -my $FiguresFile = "texexec"; -my $ArrangeFile = "texexec"; -my $SelectFile = "texexec"; -my $CopyFile = "texexec"; -my $CombineFile = "texexec"; - -sub RunModule { - my @FileNames = sort @_; - if ($FileNames[0]) { - unless ( -e $FileNames[0] ) { - my $Name = $FileNames[0]; - @FileNames = ( "$Name.tex", "$Name.mp", "$Name.pl", "$Name.pm" ); - } - foreach my $FileName (@FileNames) { - next unless -e $FileName; - my ( $Name, $Suffix ) = split( /\./, $FileName ); - next unless $Suffix =~ /(tex|mp|pl|pm)/io; - DoRunModule( $Name, $Suffix ); - } - } else { - print " module : no modules found\n\n"; - } -} - -# the next one can be more efficient: directly process ted -# file a la --use=abr-01,mod-01 - -sub checktexformatpath { - # engine support is either broken of not implemented in some - # distributions, so we need to take care of it ourselves - my $texformats ; - if (defined($ENV{'TEXFORMATS'})) { - $texformats = $ENV{'TEXFORMATS'} ; - } else { - $texformats = '' ; - } - if ($texformats eq '') { - if ($UseEnginePath) { - if ($dosish) { - if ( $TeXShell =~ /MikTeX/io ) { - $texformats = `kpsewhich --alias=$TeXExecutable --expand-var=\$TEXFORMATS` ; - } else { - $texformats = `kpsewhich --engine=$TeXExecutable --expand-var=\$TEXFORMATS` ; - } - } else { - $texformats = `kpsewhich --engine=$TeXExecutable --expand-var=\\\$TEXFORMATS` ; - } - } else { - if ($dosish) { - $texformats = `kpsewhich --expand-var=\$TEXFORMATS` ; - } else { - $texformats = `kpsewhich --expand-var=\\\$TEXFORMATS` ; - } - } - chomp($texformats) ; - } - if (($texformats !~ /web2c\/.*$TeXExecutable/) && ($texformats !~ /web2c[\/\\].*\$engine/i)) { - $texformats =~ s/(web2c\/\{)(\,\})/$1\$engine$2/ ; # needed for empty engine flags - if ($texformats !~ /web2c[\/\\].*\$ENGINE/) { - $texformats =~ s/web2c/web2c\/{\$engine,}/ ; # needed for me - } - $ENV{'TEXFORMATS'} = $texformats ; - print " fixing texformat path : $ENV{'TEXFORMATS'}\n"; - } else { - print " using texformat path : $ENV{'TEXFORMATS'}\n" if ($Verbose) ; - } - if (! defined($ENV{'ENGINE'})) { - if ($MpEngineSupport) { - $ENV{'ENGINE'} .= $MpExecutable ; - } ; - $ENV{'ENGINE'} = $TeXExecutable ; - print "fixing engine variable : $ENV{'ENGINE'}\n"; - } -} - -sub DoRunModule { - my ( $FileName, $FileSuffix ) = @_; - RunPerlScript( $TeXUtil, "--documents $FileName.$FileSuffix" ); - print " module : $FileName\n\n"; - open( MOD, ">$ModuleFile.tex" ); - # we need to signal to texexec what interface to use - open( TED, "$FileName.ted" ); - my $firstline = <TED>; - close(TED); - if ( $firstline =~ /interface=/ ) { - print MOD $firstline ; - } else { - print MOD "% interface=en\n" ; - } - # so far - print MOD "\\usemodule[abr-01,mod-01]\n"; - print MOD "\\def\\ModuleNumber{1}\n"; - print MOD "\\starttext\n"; - print MOD "\\readlocfile{$FileName.ted}{}{}\n"; - print MOD "\\stoptext\n"; - close(MOD); - checktexformatpath ; - RunConTeXtFile( $ModuleFile, "tex" ); - if ( $FileName ne $ModuleFile ) { - foreach my $FileSuffix ( "dvi", "pdf", "tui", "tuo", "log" ) { - unlink("$FileName.$FileSuffix"); - rename( "$ModuleFile.$FileSuffix", "$FileName.$FileSuffix" ); - } - } - unlink("$ModuleFile.tex"); -} - -sub RunFigures { - my @Files = @_ ; - $TypesetFigures = lc $TypesetFigures; - return unless ( $TypesetFigures =~ /[abcd]/o ); - unlink "$FiguresFile.pdf"; - if (@Files) { RunPerlScript( $TeXUtil, "--figures @Files" ) } - open( FIG, ">$FiguresFile.tex" ); - print FIG "% format=english\n"; - print FIG "\\setuplayout\n"; - print FIG " [topspace=1.5cm,backspace=1.5cm,\n"; - print FIG " header=1.5cm,footer=0pt,\n"; - print FIG " width=middle,height=middle]\n"; - if ($ForceFullScreen) { - print FIG "\\setupinteraction\n"; - print FIG " [state=start]\n"; - print FIG "\\setupinteractionscreen\n"; - print FIG " [option=max]\n"; - } - if ($BoxType ne '') { - if ($BoxType !~ /box$/io) { - $BoxType .= "box" ; - } - } - print FIG "\\starttext\n"; - print FIG "\\showexternalfigures[alternative=$TypesetFigures,offset=$PaperOffset,size=$BoxType]\n"; - print FIG "\\stoptext\n"; - close(FIG); - $ConTeXtInterface = "en"; - checktexformatpath ; - RunConTeXtFile( $FiguresFile, "tex" ); - unlink('texutil.tuf') if ( -f 'texutil.tuf' ); -} - -sub CleanTeXFileName { - my $str = shift; - $str =~ s/([\$\_\#])/\\$1/go; - $str =~ s/([\~])/\\string$1/go; - return $str; -} - -sub RunListing { - my $FileName = my $CleanFileName = shift; - my @FileNames = glob $FileName; - return unless -f $FileNames[0]; - print " input file : $FileName\n"; - if ( $BackSpace eq "0pt" ) { $BackSpace = "1.5cm" } - else { print " backspace : $BackSpace\n" } - if ( $TopSpace eq "0pt" ) { $TopSpace = "1.5cm" } - else { print " topspace : $TopSpace\n" } - open( LIS, ">$ListingFile.tex" ); - print LIS "% format=english\n"; - print LIS "\\setupbodyfont[11pt,tt]\n"; - print LIS "\\setuplayout\n"; - print LIS " [topspace=$TopSpace,backspace=$BackSpace,\n"; - print LIS " header=0cm,footer=1.5cm,\n"; - print LIS " width=middle,height=middle]\n"; - print LIS "\\setuptyping[lines=yes]\n"; - if ($Pretty) { print LIS "\\setuptyping[option=color]\n" } - print LIS "\\starttext\n"; - - foreach $FileName (@FileNames) { - $CleanFileName = lc CleanTeXFileName($FileName); - print LIS "\\page\n"; - print LIS "\\setupfootertexts[\\tttf $CleanFileName][\\tttf \\pagenumber]\n"; - print LIS "\\typefile\{$FileName\}\n"; - } - print LIS "\\stoptext\n"; - close(LIS); - $ConTeXtInterface = "en"; - checktexformatpath ; - RunConTeXtFile( $ListingFile, "tex" ); -} - -sub RunArrange { - my @files = @_; - print " backspace : $BackSpace\n"; - print " topspace : $TopSpace\n"; - print " paperoffset : $PaperOffset\n"; - if ( $AddEmpty eq '' ) { print " empty pages added : none\n" } - else { print " empty pages added : $AddEmpty\n" } - if ( $TextWidth eq '0pt' ) { print " textwidth : unknown\n" } - else { print " textwidth : $TextWidth\n" } - open( ARR, ">$ArrangeFile.tex" ); - print ARR "% format=english\n"; - print ARR "\\definepapersize\n"; - print ARR " [offset=$PaperOffset]\n"; - print ARR "\\setuplayout\n"; - print ARR " [backspace=$BackSpace,\n"; - print ARR " topspace=$TopSpace,\n"; - - if ($Markings) { - print ARR " marking=on,\n"; - print " cutmarkings : on\n"; - } - print ARR " width=middle,\n"; - print ARR " height=middle,\n"; - print ARR " location=middle,\n"; - print ARR " header=0pt,\n"; - print ARR " footer=0pt]\n"; - if ($NoDuplex) { print " duplex : off\n" } - else { - print " duplex : on\n"; - print ARR "\\setuppagenumbering\n"; - print ARR " [alternative=doublesided]\n"; - } - print ARR "\\starttext\n"; - foreach my $FileName (@files) { - print " pdffile : $FileName\n"; - print ARR "\\insertpages\n [$FileName]"; - if ( $AddEmpty ne '' ) { print ARR "[$AddEmpty]" } - print ARR "[width=$TextWidth]\n"; - } - print ARR "\\stoptext\n"; - close(ARR); - $ConTeXtInterface = "en"; - checktexformatpath ; - RunConTeXtFile( $ModuleFile, "tex" ); -} - -sub RunSelect { - my $FileName = shift; - print " pdffile : $FileName\n"; - print " backspace : $BackSpace\n"; - print " topspace : $TopSpace\n"; - print " paperoffset : $PaperOffset\n"; - if ( $TextWidth eq '0pt' ) { print " textwidth : unknown\n" } - else { print " textwidth : $TextWidth\n" } - open( SEL, ">$SelectFile.tex" ); - print SEL "% format=english\n"; - print SEL "\\definepapersize\n"; - print SEL " [offset=$PaperOffset]\n"; - if ($PaperFormat =~ /fit/) { - print SEL "\\getfiguredimensions[$FileName]\n" ; - print SEL "\\expanded{\\definepapersize[fit][width=\\figurewidth,height=\\figureheight]}\n" ; - print SEL "\\setuppapersize[fit][fit]\n"; - $PaperFormat = '' ; # avoid overloading in option file - } elsif ( $PaperFormat ne 'standard' ) { - $_ = $PaperFormat; # NO UPPERCASE ! - s/x/\*/io; - my ( $from, $to ) = split(/\*/); - if ( $to eq "" ) { $to = $from } - print " papersize : $PaperFormat\n"; - print SEL "\\setuppapersize[$from][$to]\n"; - $PaperFormat = '' ; # avoid overloading in option file - } - # - print SEL "\\setuplayout\n"; - print SEL " [backspace=$BackSpace,\n"; - print SEL " topspace=$TopSpace,\n"; - if ($Markings) { - print SEL " marking=on,\n"; - print " cutmarkings : on\n"; - } - print SEL " width=middle,\n"; - print SEL " height=middle,\n"; - print SEL " location=middle,\n"; - print SEL " header=0pt,\n"; - print SEL " footer=0pt]\n"; - print SEL "\\setupexternalfigures\n"; - print SEL " [directory=]\n"; - print SEL "\\starttext\n"; - - if ( $Selection ne '' ) { - print SEL "\\filterpages\n"; - print SEL " [$FileName][$Selection][width=$TextWidth]\n"; - } - print SEL "\\stoptext\n"; - close(SEL); - $ConTeXtInterface = "en"; - checktexformatpath ; - RunConTeXtFile( $SelectFile, "tex" ); -} - -sub RunCopy { - my $DoTrim = shift ; - my @Files = @_ ; - if ( $PageScale == 1000 ) { - print " offset : $PaperOffset\n"; - } else { - print " scale : $PageScale\n"; - if ( $PageScale < 10 ) { $PageScale = int( $PageScale * 1000 ) } - } - open( COP, ">$CopyFile.tex" ); - print COP "% format=english\n"; - print COP "\\starttext\n"; - for my $FileName (@Files) { - print " pdffile : $FileName\n"; - print COP "\\getfiguredimensions\n"; - print COP " [$FileName]\n"; - print COP " [page=1"; - if ($DoTrim) { - print COP ",\n size=trimbox"; - } - print COP "]\n"; - print COP "\\definepapersize\n"; - print COP " [copy]\n"; - print COP " [width=\\naturalfigurewidth,\n"; - print COP " height=\\naturalfigureheight]\n"; - print COP "\\setuppapersize\n"; - print COP " [copy][copy]\n"; - print COP "\\setuplayout\n"; - print COP " [page]\n"; - print COP "\\setupexternalfigures\n"; - print COP " [directory=]\n"; - print COP "\\copypages\n"; - print COP " [$FileName]\n"; - print COP " [scale=$PageScale,\n"; - if ($Markings) { - print COP " marking=on,\n"; - print " cutmarkings : on\n"; - } - if ($DoTrim) { - print COP " size=trimbox,\n"; - print " cropping to : trimbox\n"; - } - print COP " offset=$PaperOffset]\n"; - } - print COP "\\stoptext\n"; - close(COP); - $ConTeXtInterface = "en"; - checktexformatpath ; - RunConTeXtFile( $CopyFile, "tex" ); -} - -sub RunCombine { - my @Files = @_; - $Combination =~ s/x/\*/io; - my ( $nx, $ny ) = split( /\*/, $Combination, 2 ); - return unless ( $nx && $ny ); - print " combination : $Combination\n"; - open( COM, ">$CombineFile.tex" ); - print COM "% format=english\n"; - if ( $PaperFormat ne 'standard' ) { - $_ = $PaperFormat; # NO UPPERCASE ! - s/x/\*/io; - my ( $from, $to ) = split(/\*/); - if ( $to eq "" ) { $to = $from } - print " papersize : $PaperFormat\n"; - print COM "\\setuppapersize[$from][$to]\n"; - } - # - if ( $PaperOffset eq '0pt' ) { $PaperOffset = '1cm' } - print " paper offset : $PaperOffset\n"; - print COM "\\setuplayout\n"; - print COM " [topspace=$PaperOffset,\n"; - print COM " backspace=$PaperOffset,\n"; - print COM " header=0pt,\n"; - print COM " footer=1cm,\n"; - print COM " width=middle,\n"; - print COM " height=middle]\n"; - - if ($NoBanner) { - print COM "\\setuplayout\n"; - print COM " [footer=0cm]\n"; - } - print COM "\\setupexternalfigures\n"; - print COM " [directory=]\n"; - print COM "\\starttext\n"; - for my $FileName (@Files) { - next if ( $FileName =~ /^texexec/io ); - next if (($Result ne '') && ( $FileName =~ /^$Result/i )); - print " pdffile : $FileName\n"; - my $CleanFileName = CleanTeXFileName($FileName); - print COM "\\setupfootertexts\n"; - print COM " [\\tttf $CleanFileName\\quad\\quad\\currentdate\\quad\\quad\\pagenumber]\n"; - print COM "\\combinepages[$FileName][nx=$nx,ny=$ny]\n"; - print COM "\\page\n"; - } - print COM "\\stoptext\n"; - close(COM); - $ConTeXtInterface = "en"; - checktexformatpath ; - RunConTeXtFile( $CombineFile, "tex" ); -} - -sub LocatedFormatPath { # watch out $engine is lowercase in kpse - my $FormatPath = shift; - my $EnginePath = shift; - my $EngineDone = shift; - if ($Local) { - $FormatPath = '.' ; # for patrick - } else { - if ( ( $FormatPath eq '' ) && ( $kpsewhich ne '' ) ) { - unless ($EngineDone) { - my $str = $ENV{"TEXFORMATS"} ; - $str =~ s/\$engine//io ; - $ENV{"TEXFORMATS"} = $str ; - } - # expanded paths - print " assuming engine : $EnginePath\n"; - if (($UseEnginePath)&&($EngineDone)) { - if ( $TeXShell =~ /MikTeX/io ) { - $FormatPath = `$kpsewhich --alias=$EnginePath --show-path=fmt` ; - } else { - $FormatPath = `$kpsewhich --engine=$EnginePath --show-path=fmt` ; - } - } else { - $FormatPath = `$kpsewhich --show-path=fmt` ; - } - chomp($FormatPath) ; - if ( ( $FormatPath ne '' ) && $Verbose ) { - print "located formatpath (1) : $FormatPath\n"; - } - # fall back - if ($FormatPath eq '') { - if (($UseEnginePath)&&($EngineDone)) { - if ($dosish) { - if ( $TeXShell =~ /MikTeX/io ) { - $FormatPath = `$kpsewhich --alias=$EnginePath --expand-path=\$TEXFORMATS` ; - } else { - $FormatPath = `$kpsewhich --engine=$EnginePath --expand-path=\$TEXFORMATS` ; - } - } else { - $FormatPath = `$kpsewhich --engine=$EnginePath --expand-path=\\\$TEXFORMATS` ; - } - } - chomp($FormatPath) ; - # either no enginepath or failed run - if ($FormatPath eq '') { - if ($dosish) { - $FormatPath = `$kpsewhich --expand-path=\$TEXFORMATS` ; - } else { - $FormatPath = `$kpsewhich --expand-path=\\\$TEXFORMATS` ; - } - } - chomp $FormatPath ; - } - chomp($FormatPath) ; - if ( ( $FormatPath ne '' ) && $Verbose ) { - print "located formatpath (2) : $FormatPath\n"; - } - $FormatPath =~ s/\\/\//g ; - if ($FormatPath ne '') { - my @fpaths ; - if ($dosish) { - @fpaths = split(';', $FormatPath) ; - } else { - @fpaths = split(':', $FormatPath) ; - } - # take first writable unless current - foreach my $fp (@fpaths) { - # remove funny patterns - $fp =~ s/\/+$// ; - $fp =~ s/^!!// ; - $fp =~ s/unsetengine/$EnginePath/ ; - if (($fp ne '') && ($fp ne '.')) { - # correct if needed - # append engine unless engine is already there - $fp =~ "$fp/$EnginePath" if ($fp =~ /[\\\/]$EnginePath[\\\/]*$/) ; - # path may not yet be present - # check if usable format path - my $fpp = $fp ; - $fpp =~ s/\/*$EnginePath\/*// ; - if ((-d $fpp) && (-w $fpp)) { - $FormatPath = $fpp ; - last ; - } - } - } - } - $FormatPath = '.' if (($FormatPath eq '') || (! -w $FormatPath)) ; - if ( ( $FormatPath ne '' ) && $Verbose ) { - print "located formatpath (3) : $FormatPath\n"; - } - $FormatPath .= '/'; - } - if ($UseEnginePath && $EngineDone && ($FormatPath ne '') && ($FormatPath !~ /$EnginePath\/$/)) { - $FormatPath .= $EnginePath ; - unless (-d $FormatPath) { - mkdir $FormatPath ; - } - $FormatPath .= '/' ; - } - } - print " using formatpath : $FormatPath\n" if $Verbose ; - return $FormatPath; -} - -sub RunOneFormat { - my ($FormatName) = @_; - my @TeXFormatPath; - my $TeXPrefix = ""; - if ( ( $fmtutil ne "" ) && ( $FormatName !~ /metafun|mptopdf/io ) ) { - # could not happen, not supported any more - my $cmd = "$fmtutil --byfmt $FormatName"; - MakeUserFile; # this works only when the path is kept - MakeResponseFile; - $Problems = System("$cmd"); - RemoveResponseFile; - RestoreUserFile; - } else { - $Problems = 1; - } - if ($Problems) { - $Problems = 0; - if ( $TeXExecutable =~ /etex|eetex|pdfetex|pdfeetex|pdfxtex|xpdfetex|eomega|aleph|xetex/io ) { - $TeXPrefix = "*"; - } - my $CurrentPath = cwd(); - my $TheTeXFormatPath = LocatedFormatPath($TeXFormatPath, $TeXExecutable,1); - if ( $TheTeXFormatPath ne '' ) { chdir $TheTeXFormatPath } - MakeUserFile; - MakeResponseFile; - $own_quote = ($TeXProgramPath =~ m/^[^\"].* / ? "\"" : "") ; - my $cmd = - "$own_quote$TeXProgramPath$TeXExecutable$own_quote $TeXVirginFlag " - . "$TeXPassString $PassOn ${TeXPrefix}$FormatName"; - $Problems = System($cmd) ; - RemoveResponseFile; - RestoreUserFile; - - if ( ( $TheTeXFormatPath ne '' ) && ( $CurrentPath ne '' ) ) { - print "\n"; - if ($UseEnginePath) { - print " used engineformatpath : $TheTeXFormatPath\n"; - } else { - print " used formatpath : $TheTeXFormatPath\n"; - } - print "\n"; - chdir $CurrentPath; - } - } -} - -sub RunFormats { - my $ConTeXtFormatsPrefix; - my $MetaFunDone = 0; - if (@ARGV) { @ConTeXtFormats = @ARGV } - elsif ( $UsedInterfaces ne '' ) { - @ConTeXtFormats = split /[\,\s]/, $UsedInterfaces; - } - if ($Format) { @ConTeXtFormats = $Format; $ConTeXtFormatsPrefix = ''; } - else { $ConTeXtFormatsPrefix = "cont-"; } - if ( $TeXHashExecutable ne '' ) { - unless ($FastMode) { - $own_quote = ($TeXProgramPath =~ m/^[^\"].* / ? "\"" : "") ; - my $cmd = "$own_quote$TeXProgramPath$TeXHashExecutable$own_quote"; - print "\n"; - print " TeX hash binary : $TeXProgramPath$TeXHashExecutable\n"; - print " comment : hashing may take a while ...\n"; - System($cmd); - } - } - foreach my $Interface (@ConTeXtFormats) { - if ( $Interface eq $MetaFun ) { - RunMpFormat($MetaFun); - $MetaFunDone = 1; - } elsif ( $Interface eq $MpToPdf ) { - if ( $TeXExecutable =~ /pdf/io ) { RunOneFormat("$MpToPdf") } - } else { - RunOneFormat("$ConTeXtFormatsPrefix$Interface"); - } - } - print "\n"; - print " TeX binary : $TeXProgramPath$TeXExecutable\n"; - print " format(s) : @ConTeXtFormats\n\n"; -} - -sub RunMpFormat { - # engine is not supported by MP - my $MpFormat = shift; - return if ( $MpFormat eq '' ); - my $CurrentPath = cwd(); - my $TheMpFormatPath = LocatedFormatPath($MpFormatPath,$MpExecutable,$MpEngineSupport); - if ( $TheMpFormatPath ne '' ) { chdir $TheMpFormatPath } - $own_quote = ($MpExecutable =~ m/^[^\"].* / ? "\"" : "") ; - my $cmd = - "$own_quote$MpExecutable$own_quote $MpVirginFlag $MpPassString $MpFormat"; - System($cmd ) ; - if ( ( $TheMpFormatPath ne '' ) && ( $CurrentPath ne '' ) ) { - print "\n"; - print " used formatpath : $TheMpFormatPath\n"; - print "\n"; - chdir $CurrentPath; - } -} - - -my $dir = File::Temp::tempdir(CLEANUP=>1) ; -my ($fh, $filename) = File::Temp::tempfile(DIR=>$dir, UNLINK=>1); - -sub RunFiles { - my $currentpath = cwd() ; - my $oldrunpath = $RunPath ; - # new - checktexformatpath ; - # test if current path is writable - if (! -w "$currentpath") { - print " current path readonly : $currentpath\n"; - # - # we cannot use the following because then the result will - # also be removed and users will not know where to look - # - # $RunPath = File::Temp::tempdir(CLEANUP=>1) ; - # if ($RunPath) { - # print " using temp path : $RunPath\n"; - # } else { - # print " problematic temp path : $currentpath\n"; - # exit ; - # } - # - foreach my $d ($ENV{"TMPDIR"},$ENV{"TEMP"},$ENV{"TMP"},"/tmp") { - if ($d && -e $d) { $RunPath = $d ; last ; } - } - if ($TempDir eq '') { - print " provide temp path for : $RunPath\n"; - exit ; - } elsif ($RunPath ne $oldrunpath) { - chdir ($RunPath) ; - unless (-e $TempDir) { - print " creating texexec path : $TempDir\n"; - mkdir ("$TempDir", 077) - } - if (-e $TempDir) { - $RunPath += $TempDir ; - } else { - # we abort this run because on unix an invalid tmp - # path can be an indication of a infected system - print " problematic temp path : $RunPath\n"; - exit ; - } - } else { - print " no writable temp path : $RunPath\n"; - exit ; - } - } - # test if we need to change paths - if (($RunPath ne "") && (-w "$RunPath")) { - print " changing to path : $RunPath\n"; - $InpPath = $currentpath ; - chdir ($RunPath) ; - } - # start working - if ($PdfArrange) { - my @arrangedfiles = (); - foreach my $JobName (@ARGV) { - unless ( $JobName =~ /.*\.pdf$/oi ) { - if ( -f "$JobName.pdf" ) { $JobName .= ".pdf" } - else { $JobName .= ".PDF" } - } - push @arrangedfiles, $JobName; - } - if (@arrangedfiles) { RunArrange(@arrangedfiles) } - } elsif ( ($PdfSelect) || ($PdfCopy) || ($PdfTrim) || ($PdfCombine) ) { - my $JobName = $ARGV[0]; - if ( $JobName ne '' ) { - unless ( $JobName =~ /.*\.pdf$/oi ) { - if ( -f "$JobName.pdf" ) { $JobName .= ".pdf" } - else { $JobName .= ".PDF" } - } - if ($PdfSelect) { - RunSelect($JobName) ; - } elsif ($PdfCopy) { - # RunCopy($JobName) ; - RunCopy(0,@ARGV) ; - } elsif ($PdfTrim) { - # RunCopy($JobName) ; - RunCopy(1,@ARGV) ; - } else { - # RunCombine ($JobName) ; - RunCombine(@ARGV); - } - } - } elsif ($TypesetModule) { - RunModule(@ARGV); - } else { - my $JobSuffix = "tex"; - foreach my $JobName (@ARGV) { - next if ($JobName =~ /^\-/io) ; - # start experiment - full name spec including suffix is prerequisite - if (($StartLine>0) && ($EndLine>=$StartLine) && (-e $JobName)) { - if (open(INP,$JobName) && open(OUT,'>texexec.tex')) { - print " writing partial file : $JobName\n"; - my $Line = 1 ; - my $Preamble = 1 ; - while (my $str = <INP>) { - if ($Preamble) { - if ($str =~ /\\start(text|tekst|product|project|component)/io) { - $Preamble = 0 ; - } else { - print OUT $str; - } - } elsif ($Line==$StartLine) { - print OUT "\\starttext\n" ; # todo: multilingual - print OUT $str ; - } elsif ($Line==$EndLine) { - print OUT $str ; - print OUT "\\stoptext\n" ; # todo: multilingual - last ; - } elsif (($Line>$StartLine) && ($Line<$EndLine)) { - print OUT $str ; - } - $Line += 1 ; - } - close(INP) ; - close(OUT) ; - $JobName = 'texexec.tex' ; - print " using job name : $JobName\n"; - } - } - # end experiment - if ( $JobName =~ s/\.(\w+)$//io ) { $JobSuffix = $1 } - if ( ( $Format eq '' ) || ( $Format =~ /^cont.*/io ) ) { - RunConTeXtFile( $JobName, $JobSuffix ); - } else { - RunSomeTeXFile( $JobName, $JobSuffix ); - } - unless ( -s "$JobName.log" ) { unlink("$JobName.log") } - unless ( -s "$JobName.tui" ) { unlink("$JobName.tui") } - } - } -} - -my $MpTmp = "tmpgraph"; # todo: prefix met jobname -my $MpKep = "$MpTmp.kep"; # sub => MpTmp("kep") -my $MpLog = "$MpTmp.log"; -my $MpBck = "$MpTmp.bck"; -my $MpTex = "$MpTmp.tex"; -my $MpDvi = "$MpTmp.dvi"; - -my %mpbetex; - -sub RunMP { ########### - if ( ($MpExecutable) && ($MpToTeXExecutable) && ($DviToMpExecutable) ) { - foreach my $RawMpName (@ARGV) { - my ( $MpName, $Rest ) = split( /\./, $RawMpName, 2 ); - my $MpFile = "$MpName.mp"; - if ( -e $MpFile - and ( -s $MpFile > 25 ) ) # texunlink makes empty file - { - unlink "$MpName.mpt"; - doRunMP( $MpName, 0 ); - # test for graphics, new per 14/12/2000 - my $mpgraphics = checkMPgraphics($MpName); - # test for labels - my $mplabels = checkMPlabels($MpName); - if ( $mpgraphics || $mplabels ) { - doRunMP( $MpName, $mplabels ); - } - } - } - } -} - -my $mpochecksum = ''; - -#~ sub checkMPgraphics { # also see makempy - #~ my $MpName = shift; - #~ if ( $MakeMpy ne '' ) { $MpName .= " --$MakeMpy " } # extra switches - #~ if ($MpyForce) { $MpName .= " --force " } # dirty - #~ else { - #~ return 0 unless -s "$MpName.mpo" > 32; - #~ return 0 unless ( open( MPO, "$MpName.mpo" ) ); - #~ $mpochecksum = do { local $/; unpack( "%32C*", <MPO> ) % 65535 }; - #~ close(MPO); - #~ if ( open( MPY, "$MpName.mpy" ) ) { - #~ my $str = <MPY>; - #~ chomp $str; - #~ close(MPY); - #~ if ( $str =~ /^\%\s*mpochecksum\s*\:\s*(\d+)/o ) { - #~ return 0 if ( ( $mpochecksum eq $1 ) && ( $mpochecksum ne 0 ) ); - #~ } - #~ } - #~ } - #~ RunPerlScript( "makempy", "$MpName" ); - #~ print " second MP run needed : text graphics found\n"; - #~ return 1; -#~ } - -sub checkMPgraphics { # also see makempy - my $MpName = shift; - if ( $MakeMpy ne '' ) { $MpName .= " --$MakeMpy " } # extra switches - if ($MpyForce) { $MpName .= " --force " } # dirty - else { - return 0 unless -s "$MpName.mpo" > 32; - return 0 unless ( open( MPO, "$MpName.mpo" ) ); - $mpochecksum = do { local $/; Digest::MD5::md5_hex(<MPO>) ; }; - close(MPO); - if ( open( MPY, "$MpName.mpy" ) ) { - my $str = <MPY>; - chomp $str; - close(MPY); - if ( $str =~ /^\%\s*mpochecksum\s*\:\s*([a-fA-F0-9]+)/o ) { - return 0 if ( ( $mpochecksum eq $1 ) && ( $mpochecksum ne '' ) ); - } - } - } - RunPerlScript( "makempy", "$MpName" ); - print " second MP run needed : text graphics found\n"; - return 1; -} - -sub checkMPlabels { - my $MpName = shift; - return 0 unless ((-f "$MpName.mpt") && ((-s "$MpName.mpt")>10) ); - return 0 unless open( MP, "$MpName.mpt" ); - my $n = 0; - my $t = "" ; - while (<MP>) { - if (/% setup : (.*)/o) { - $t = $1 ; - } else { - $t = "" ; - } - if (/% figure (\d+) : (.*)/o) { - if ($t ne "") { - $mpbetex{$1} .= "$t\n" ; - $t = "" ; - } - $mpbetex{$1} .= "$2\n"; - ++$n ; - } - } - close(MP); - print " second MP run needed : $n tex labels found\n" if $n; - return $n; -} - -sub doMergeMP { - # make sure that the verbatimtex ends up before btex etc - my ($n,$str) = @_ ; - if ($str =~ /(.*?)(verbatimtex.*?etex)\s*\;(.*)/mois) { - return "beginfig($n)\;\n$1$2\;\n$mpbetex{$n}\n$3\;endfig\;\n" ; - } else { - return "beginfig($n)\;\n$mpbetex{$n}\n$str\;endfig\;\n" ; - } -} - -sub doRunMP { ########### - my ( $MpName, $MergeBE ) = @_; - my $TexFound = 0; - my $MpFile = "$MpName.mp"; - if ( open( MP, $MpFile ) ) { # fails with % - my $MPdata = ""; - while (<MP>) { - unless (/^\%/) { $MPdata .= $_ } - } - $_ = $MPdata; - close(MP); - - # save old file - unlink($MpKep); - return if ( -e $MpKep ); - rename( $MpFile, $MpKep ); - # check for tex stuff - - $TexFound = $MergeBE || /btex .*? etex/o; - - # shorten lines into new file if okay - unless ( -e $MpFile ) { - open( MP, ">$MpFile" ); - s/(btex.*?)\;(.*?etex)/$1\@\@\@$2/gmois; - s/(\".*?)\;(.*?\")/$1\@\@\@$2/gmois; # added - s/\;/\;\n/gmois; - s/\n\n/\n/gmois; - s/(btex.*?)\@\@\@(.*?etex)/$1\;$2/gmois; - s/(\".*?)\@\@\@(.*?\")/$1\;$2/gmois; # added - # merge labels - if ($MergeBE) { - # i hate this indirect (sub regexp) mess - s/beginfig\s*\((\d+)\)\s*\;(.*?)endfig\s*\;/doMergeMP($1,$2)/gems ; - } - unless (/beginfig\s*\(\s*0\s*\)/gmois) { - if (defined($mpbetex{0})) { # test added, warning - print MP $mpbetex{0} ; - } - } - print MP $_; - print MP "\n" . "end" . "\n"; - close(MP); - } - if ($TexFound) { - print " metapost to tex : $MpName\n"; - $own_quote = ($MpToTeXExecutable =~ m/^[^\"].* / ? "\"" : "") ; - $Problems = - System("$own_quote$MpToTeXExecutable$own_quote $MpFile > $MpTex"); - if ( -e $MpTex && !$Problems ) { - open( TMP, ">>$MpTex" ); - print TMP "\\end\{document\}\n"; # to be sure - close(TMP); - if ( ( $Format eq '' ) || ( $Format =~ /^cont.*/io ) ) { - $OutputFormat = "dvips"; - RunConTeXtFile( $MpTmp, "tex" ); - } else { - RunSomeTeXFile( $MpTmp, "tex" ); - } - if ( -e $MpDvi && !$Problems ) { - print " dvi to metapost : $MpName\n"; - $own_quote = ($DviToMpExecutable =~ m/^[^\"].* / ? "\"" : "") ; - $Problems = System("$own_quote$DviToMpExecutable$own_quote $MpDvi $MpName.mpx"); - } - unlink $MpBck; - rename $MpTex, $MpBck; - unlink $MpDvi; - } - } - print " metapost : $MpName\n"; - $own_quote = ($MpExecutable =~ m/^[^\"].* / ? "\"" : "") ; - my $cmd = "$own_quote$MpExecutable$own_quote"; - if ($EnterBatchMode) { $cmd .= " $MpBatchFlag " } - if ($EnterNonStopMode) { $cmd .= " $MpNonStopFlag " } - if ( ( $MpFormat ne '' ) && ( $MpFormat !~ /(plain|mpost)/oi ) ) { - print " format : $MpFormat\n"; - $cmd .= " $MpPassString $MpFormatFlag$MpFormat "; - } - # prevent nameclash, experimental - my $MpMpName = "$MpName"; - $Problems = System("$cmd $MpMpName"); - open( MPL, "$MpName.log" ); - while (<MPL>) # can be one big line unix under win - { - while (/^l\.(\d+)\s/gmois) { - print " error in metapost run : $MpName.mp:$1\n"; - } - } - close(MPL) ; - unlink "mptrace.tmp"; - rename( $MpFile, "mptrace.tmp" ); - if ( -e $MpKep ) { - unlink($MpFile); - rename( $MpKep, $MpFile ); - } - } -} - -sub RunMPX { - my $MpName = shift; - $MpName =~ s/\..*$//o; - my $MpFile = $MpName . ".mp"; - if ( ($MpToTeXExecutable) - && ($DviToMpExecutable) - && ( -e $MpFile ) - && ( -s $MpFile > 5 ) - && open( MP, $MpFile ) ) - { - local $/ = "\0777"; - $_ = <MP>; - close(MP); - if (/(btex|etex|verbatimtex)/mos) { - print " generating mpx file : $MpName\n"; - $own_quote = ($MpToTeXExecutable =~ m/^[^\"].* / ? "\"" : "") ; - $Problems = - System("$own_quote$MpToTeXExecutable$own_quote $MpFile > $MpTex"); - if ( -e $MpTex && !$Problems ) { - open( TMP, ">>$MpTex" ); - print TMP "\\end\n"; # to be sure - close(TMP); - checktexformatpath ; - if ( ( $Format eq '' ) || ( $Format =~ /^cont.*/io ) ) { - RunConTeXtFile( $MpTmp, "tex" ); - } else { - RunSomeTeXFile( $MpTmp, "tex" ); - } - if ( -e $MpDvi && !$Problems ) { - $own_quote = ($DviToMpExecutable =~ m/^[^\"].* / ? "\"" : "") ; - $Problems = - System("$own_quote$DviToMpExecutable$own_quote $MpDvi $MpName.mpx"); - } - unlink $MpTex; - unlink $MpDvi; - } - } - } -} - -sub load_set_file { - my %new; - my %old; - my ( $file, $trace ) = @_; - if ( open( BAT, $file ) ) { - while (<BAT>) { - chomp; - if (/\s*SET\s+(.+?)\=(.+)\s*/io) { - my ( $var, $val ) = ( $1, $2 ); - $val =~ s/\%(.+?)\%/$ENV{$1}/goi; - unless ( defined( $old{$var} ) ) { - if ( defined( $ENV{$var} ) ) { $old{$var} = $ENV{$var} } - else { $old{$var} = "" } - } - $ENV{$var} = $new{$var} = $val; - } - } - close(BAT); - } - if ($trace) { - foreach my $key ( sort keys %new ) { - if ( $old{$key} ne $new{$key} ) { - print " changing env variable : '$key' from '$old{$key}' to '$new{$key}'\n"; - } elsif ( $old{$key} eq "" ) { - print " setting env variable : '$key' to '$new{$key}'\n"; - } else { - print " keeping env variable : '$key' at '$new{$key}'\n"; - } - } - print "\n"; - } -} - -if ( $SetFile ne "" ) { load_set_file( $SetFile, $Verbose ) } - -sub check_texmf_root { } -sub check_texmf_tree { } - -sub AnalyzeVersion - { my $str = join("\n", @_) ; - my ($texengine,$type) = ('unknown', 'unknown'); - open (LOG, "<texvers.log") ; - while (<LOG>) - { /^\s*This is (.*(pdf)?(|e|x)TeX.*?)$/o and $texengine = $1 ; - /^\s*ConTeXt (.*int: ([a-z]+).*?)\s*$/o and $type = $1; } - $type =~ s/ int: ([a-z]+)//; - $texengine =~ s/ Version//; - $texengine =~ s/ \(format.*$//; - close (LOG); - return ($texengine,$type) } - -sub show_version_info { - my ($texengine,$type); - open (TEX,">texvers.tex") ; - print TEX "\\bye " ; - close (TEX) ; - my $texutil = `$TeXUtil --help`; - $texutil =~ s/.*(TeXUtil[^\n]+)\n.*?$/$1/s; - print " texexec :$Program\n" ; - print " texutil : $texutil" ; - my $contexttext = `$kpsewhich context.tex`; - my $contextversion = "<not found>"; - if ($contexttext) { - chop $contexttext; - { local $/; - open (IN,"<$contexttext"); - $contextversion = <IN>; - close IN; - } - $contextversion =~ s/.*contextversion\{([0-9\.\:\s]+)\}.*/$1/s; - } - $EnterBatchMode = 1; - $Format = 'cont-en'; - my $cmd = PrepRunTeX("texvers","tex",'') ; - ($texengine,$type) = AnalyzeVersion(Pipe($cmd)) ; - print " tex : $texengine\n" ; - print " context : ver: $contextversion\n" ; - print " cont-en : $type\n" ; - foreach my $a (qw(cz de fr it nl ro uk xx)) { - my $test = Pipe("$kpsewhich -format='fmt' cont-$a") ; - if (defined $test && $test) { - $Format = 'cont-' . $a; - $cmd = PrepRunTeX("texvers","tex",''); - ($texengine,$type) = AnalyzeVersion(Pipe($cmd)) ; - print " cont-$a : $type\n" ; - } - } - unlink <texvers.*>; -} - -# the main thing - -if ($HelpAsked) { - show_help_info -} elsif ($Version) { - show_version_info -} elsif ($TypesetListing) { - check_texmf_root; - check_texmf_tree; - RunListing(@ARGV); -} elsif ($TypesetFigures) { - check_texmf_root; - check_texmf_tree; - RunFigures(@ARGV); -} elsif ($DoMPTeX) { - check_texmf_root; - check_texmf_tree; - RunMP; -} elsif ($DoMPXTeX) { - check_texmf_root; - check_texmf_tree; - RunMPX( $ARGV[0] ); -} elsif ($MakeFormats) { - check_texmf_root; - check_texmf_tree; - if ( $MpDoFormat ne '' ) { - RunMpFormat($MpDoFormat) ; - } - else { - RunFormats ; - } -} elsif (@ARGV) { - check_texmf_root; - check_texmf_tree; - @ARGV = <@ARGV>; - RunFiles; -} elsif ( !$HelpAsked ) { - show_help_options; -} - -$TotalTime = time - $TotalTime; - -unless ($HelpAsked) { print "\n total run time : $TotalTime seconds\n" } - -print "\n" ; -print " warning : use 'texmfstart texexec' instead\n" ; - -if ($Problems) { exit 1 } - -__DATA__ -arrange process and arrange ------------ -batch run in batch mode (don't pause) ------------ -nonstop run in non stop mode (don't pause) ------------ -centerpage center the page on the paper ------------ -color enable color (when not yet enabled) ------------ -usemodule load some modules first -=name list of modules ------------ -xmlfilter apply XML filter -=name list of filters ------------ -environment load some environments first -=name list of environments ------------ -fast skip as much as possible ------------ -figures typeset figure directory -=a room for corrections -=b just graphics -=c one (cropped) per page -paperoffset room left at paper border -fullscreen force full screen mode (pdf) ------------ -screensaver turn graphic file into a (pdf) full screen file ------------ -final add a final run without skipping ------------ -format fmt file -=name format file (memory dump) ------------ -mpformat mem file -=name format file (memory dump) ------------ -interface user interface -=en English -=nl Dutch -=de German -=fr French -=cz Czech -=uk British -=it Italian ------------ -language main hyphenation language -=xx standard abbreviation ------------ -listing produce a verbatim listing -backspace inner margin of the page -topspace top/bottom margin of the page -pretty enable pretty printing -color use color for pretty printing ------------ -make build format files -language patterns to include -bodyfont bodyfont to preload -response response interface language -format TeX format -mpformat MetaPost format -program TeX program ------------ -mode running mode -=list modes to set ------------ -module typeset tex/pl/mp module ------------ -mptex run an MetaPost plus btex-etex cycle ------------ -mpxtex generate an MetaPost mpx file ------------ -noarrange process but ignore arrange ------------ -nomp don't run MetaPost at all ------------ -nomprun don't run MetaPost at runtime ------------ -automprun MetaPost at runtime when needed ------------ -once run TeX only once (no TeXUtil either) ------------ -output specials to use -=pdftex Han The Thanh's pdf backend -=dvips Tomas Rokicky's dvi to ps converter -=dvipsone YandY's dvi to ps converter -=dviwindo YandY's windows previewer -=dvipdfm Mark Wicks' dvi to pdf converter -=dvipdfmx Jin-Hwan Cho's extended dvipdfm ------------ -passon switches to pass to TeX (--src for MikTeX) ------------ -pages pages to output -=odd odd pages -=even even pages -=x,y:z pages x and y to z ------------ -paper paper input and output format -=a4a3 A4 printed on A3 -=a5a4 A5 printed on A4 ------------ -path document source path -=string path ------------ -pdf produce PDF directly using pdf(e)tex ------------ -pdfarrange arrange pdf pages -paperoffset room left at paper border -paper paper format -noduplex single sided -backspace inner margin of the page -topspace top/bottom margin of the page -markings add cutmarks -background -=string background graphic -addempty add empty page after -textwidth width of the original (one sided) text ------------ -pdfcombine combine pages to one page -paperformat paper format -combination n*m pages per page -paperoffset room left at paper border -nobanner no footerline ------------ -pdfcopy scale pages down/up -scale new page scale -paperoffset room left at paper border -markings add cutmarks -background -=string background graphic ------------ -pdfselect select pdf pages -selection pages to select -=odd odd pages -=even even pages -=x,y:z pages x and y to z -paperoffset room left at paper border -paperformat paper format -backspace inner margin of the page -topspace top/bottom margin of the page -markings add cutmarks -background -=string background graphic -addempty add empty page after -textwidth width of the original (one sided) text ------------ -print page imposition scheme -=up 2 pages per sheet doublesided -=down 2 rotated pages per sheet doublesided ------------ -result resulting file -=name filename ------------ -input input file (if used) -=name filename ------------ -suffix resulting file suffix -=string suffix ------------ -runs maximum number of TeX runs -=n number of runs ------------ -silent minimize (status) messages ------------ -tex TeX binary -=name binary of executable ------------ -textree additional texmf tree to be used -=path subpath of tex root ------------ -texroot root of tex trees -=path tex root ------------ -verbose shows some additional info ------------ -help show this or more, e.g. '--help interface' ------------ -alone bypass utilities (e.g. fmtutil for non-standard fmts) ------------ -texutil force TeXUtil run ------------ -version display various version information ------------ -setfile load environment (batch) file diff --git a/scripts/context/perl/texexec.rme b/scripts/context/perl/texexec.rme deleted file mode 100644 index 43f142f9d..000000000 --- a/scripts/context/perl/texexec.rme +++ /dev/null @@ -1,169 +0,0 @@ -% == introduction == -% -% This is 'texexec.ini', the file used by texexec to determine where -% to find files, what TeX to use, what flags to pass, etc. Although -% TeXexec tries to locate things itself, a little help is sometimes -% needed. One can influence texexec by setting some variables. These -% are only needed when the automatic determined settings fail. -% -% == interfacing == -% -% UsedInterfaces nl,en the formats generated with --make -% UserInterface nl the default format used -% -% == binaries == -% -% TeXExecutable pdfetex the TeX binary to use -% MpExecutable mpost the MetaPost binary to use -% MpToTeXExecutable mpto the MetaPost to TeX converter -% DviToMpExecutable dvitomp the DVI to MetaPost converter -% -% == Scripts == -% -% DviSpecialScript dvispec the DVI special filter script -% -% == flags == -% -% TeXFormatFlag -fmt= the format introducer -% TeXVirginFlag -ini the format generation switch -% -% == paths == -% -% TeXFormatPath texmf/... fmt files -% ConTeXtPath texmf/tex/context/base sources -% SetupPath texmf/tex/base/user cont-sys/usr file -% TeXScriptsPath texmf/context/perltk scripts -% TeXFontsPath texmf font files -% -% MpFormatPath TeXFormatPath mem files -% -% == the main shell setting == -% -% As shown below, one can define his/her own sections. We default to -% the teTeX/fpTeX web2c based settings. - -set TeXShell to tetex -%set TeXShell to fptex -%set TeXShell to miktex -%set TeXShell to private - -% == setting up the variables == -% -% Here are some general defaults. They can be overruled later. - -set UseEnginePath to true - -set UsedInterfaces to en nl metafun mptopdf -set UserInterface to en - -set TeXExecutable to tex - -set MpExecutable to mpost -set MpToTeXExecutable to mpto -set DviToMpExecutable to dvitomp -set DviSpecialScript to dvispec - -set MpFormat to metafun - -set TeXFormatFlag to & -set MpFormatFlag to & - -% For teTeX the next settings will do. - -% -default-translate-file=cp8bit -file-line-error-style - -for tetex set TeXHashExecutable to mktexlsr -for tetex set TeXExecutable to pdfetex -for tetex set TeXVirginFlag to -ini -for tetex set TeXPassString to -progname=context -for tetex set TeXBatchFlag to -int=batchmode -for tetex set TeXNonStopFlag to -int=nonstopmode -for tetex set MpToTeXExecutable to mpto -for tetex set MpVirginFlag to -ini -for tetex set MpPassString to -progname=mpost -for tetex set MpBatchFlag to -int=batchmode -for tetex set MpNonStopFlag to -int=nonstopmode - -% These also apply to fpTeX. - -% -default-translate-file=cp8bit -file-line-error-style - -for fptex set TeXHashExecutable to mktexlsr -for fptex set TeXExecutable to pdfetex -for fptex set TeXVirginFlag to -ini -for fptex set TeXPassString to -progname=context -for fptex set TeXBatchFlag to -int=batchmode -for fptex set TeXNonStopFlag to -int=nonstopmode -for fptex set MpToTeXExecutable to mpto -for fptex set MpVirginFlag to -ini -for fptex set MpPassString to -progname=mpost -for fptex set MpBatchFlag to -int=batchmode -for fptex set MpNonStopFlag to -int=nonstopmode - -% a downward compatibility test (<7.5.3), next year we will use -8bit - -for tetex set TeXVirginFlag to -ini -translate-file=natural.tcx -for fptex set TeXVirginFlag to -ini -translate-file=natural.tcx -for tetex set MpVirginFlag to -ini -translate-file=natural.tcx -for fptex set MpVirginFlag to -ini -translate-file=natural.tcx - -for tetex set TeXPassString to -progname=context -translate-file=natural.tcx -for fptex set TeXPassString to -progname=context -translate-file=natural.tcx -for tetex set MpPassString to -progname=mpost -translate-file=natural.tcx -for fptex set MpPassString to -progname=mpost -translate-file=natural.tcx - -% MikTeX users probably have to set up some paths too. - -for miktex set TeXHashExecutable to initexmf --update-fndb -for miktex set TeXExecutable to pdfetex -for miktex set TeXVirginFlag to --initialize -for miktex set TeXPassString to --alias=context --translate-file=natural.tcx -for miktex set TeXBatchFlag to --interaction=batchmode -for miktex set TeXNonStopFlag to --interaction=nonstopmode -for miktex set MpToTeXExecutable to mpto -for miktex set MpVirginFlag to --initialize -for miktex set MpPassString to --alias=mpost --translate-file=natural.tcx -for miktex set MpBatchFlag to --interaction=batchmode -for miktex set MpNonStopFlag to --interaction=nonstopmode - -for miktex set TeXFormatFlag to --undump= -for miktex set MpFormatFlag to --undump= - -% These are the settings used on some machines at PRAGMA ADE that -% don't use the texmf tree. They can serve as an example for local -% settings. Local settings should either be added to the previous -% one, or go without the 'for' directives. Consider these -% settings as an example. - -for private set UsedInterfaces to en nl -for private set UserInterface to nl -for private set ConTeXtPath to t:/sources/ -for private set SetupPath to t:/perl/ -for private set TeXScriptsPath to t:/perl/ - -% == read this too == -% -% If this file is called 'texexec.rme', copy it to 'texexec.ini', -% check the settings above, change them according to your TeX -% distribution, and say: -% -% texexec --verbose -% -% When set up properly, you should see your local settings fly by. -% When these settings are ok, the next call should work: -% -% texexec --make -% -% and you should be able to process a file by saying -% -% texexec filename -% -% See 'mtexexec.pdf' for more information on the flags you can use with -% 'texexec'. Also make sure you have the 'texutil' script installed in -% the same path as 'texexec'. - -% Experimental -% -% set TcXPath to d:/tex/texmf/web2c -% set FmtLanguage to pl -% set FmtBodyFont to plr diff --git a/scripts/context/perl/texfind.pl b/scripts/context/perl/texfind.pl deleted file mode 100644 index 53a560c79..000000000 --- a/scripts/context/perl/texfind.pl +++ /dev/null @@ -1,270 +0,0 @@ -eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q' - if 0; - -#D \module -#D [ file=texfind.pl, -#D version=1998.05.10, -#D title=\TEXFIND, -#D subtitle=searching files, -#D author=Hans Hagen, -#D date=\currentdate, -#D copyright={PRAGMA / Hans Hagen \& Ton Otten}] -#C -#C This module is part of the \CONTEXT\ macro||package and is -#C therefore copyrighted by \PRAGMA. See licen-en.pdf for -#C details. - -# test with "doif(un|)defined" - -use strict ; -use Getopt::Long ; -use File::Find ; -use Cwd ; -use Tk ; -use Tk::widgets ; -use Tk::ROText ; - -use FindBin ; -use lib $FindBin::Bin ; -use path_tre ; - -my $FileSuffix = 'tex' ; -my $SearchString = '' ; -my $Recurse = 0 ; -my $NumberOfHits = 0 ; -my $QuitSearch = 0 ; -my $Location = '' ; -my $currentpath = '.' ; - -my @FileList ; - -my ($dw, $mw, $log, $sea, $fil, $num, $but, $dir, $loc) ; - -$mw = MainWindow -> new () ; -$dw = MainWindow -> new () ; - -$mw -> protocol( 'WM_DELETE_WINDOW' => sub { exit } ) ; -$dw -> protocol( 'WM_DELETE_WINDOW' => sub { exit } ) ; - -$log = $mw -> Scrolled ( 'ROText' , - -scrollbars => 'se' , - -font => 'courier' , - -wrap => 'none' , - -width => 65 , - -height => 22 ) - -> pack ( -side => 'bottom' , - -padx => 2 , - -pady => 2 , - -expand => 1 , - -fill => 'both' ) ; - -$sea = $mw -> Entry ( -textvariable => \$SearchString , - -font => 'courier' , - -width => 20 ) - -> pack ( -side => 'left' , - -padx => 2 , - -pady => 2 ) ; - -$fil = $mw -> Entry ( -textvariable => \$FileSuffix , - -font => 'courier' , - -width => 5 ) - -> pack ( -side => 'left' , - -padx => 2 , - -pady => 2 ) ; - -$but = $mw -> Checkbutton ( -variable => \$Recurse , - -text => 'recurse' ) - -> pack ( -side => 'left' ) ; - -$num = $mw -> Entry ( -textvariable => \$NumberOfHits , - -font => 'courier' , - -justify => 'right' , - -width => 5 ) - -> pack ( -side => 'right' , - -padx => 2 , - -pady => 2 ) ; - -$loc = $mw -> Entry ( -textvariable => \$Location , - -font => 'courier' , - -width => 8 ) - -> pack ( -side => 'right' , - -padx => 2 , - -pady => 2 ) ; - -sub BuildDir - { if (Exists($dir)) { $dir -> destroy } ; - $dir = $dw -> Scrolled ( 'PathTree' , - -scrollbars => 'se' ) - -> pack ( -expand => 1 , - -fill => 'both' , - -padx => 2 , - -pady => 2 ) ; - $dir -> configure ( -font => 'courier' , - -height => 24 , - -width => 65 , - -selectbackground => 'blue3' , - -browsecmd => \&ChangePath ) ; - $dir -> bind ('<Return>' , \&ShowFile ) ; - $dir -> bind ('<Double-1>' , \&ShowFile ) } - -BuildDir ; - -sub ShowFile { $mw -> raise ; $sea -> focusForce } -sub ShowPath { $dw -> raise ; $dir -> focusForce } - -$log -> tagConfigure ( 'found', -foreground => 'green3' ) ; -$log -> tagConfigure ( 'title', -foreground => 'blue3' ) ; - -$sea -> bind ('<Return>' , \&LocateStrings ) ; -$fil -> bind ('<Return>' , \&LocateStrings ) ; -$loc -> bind ('<Return>' , \&ChangeLocation ) ; -$log -> bind ('<Return>' , \&ShowPath ) ; - -$sea -> bind ('<KeyPress>' , \&QuitSearch ) ; -$fil -> bind ('<KeyPress>' , \&QuitSearch ) ; -$loc -> bind ('<KeyPress>' , \&QuitSearch ) ; - -$sea -> bind ('<Escape>' , \&QuitSearch ) ; -$fil -> bind ('<Escape>' , \&QuitSearch ) ; -$loc -> bind ('<Escape>' , \&QuitSearch ) ; -$log -> bind ('<Escape>' , \&QuitSearch ) ; - -$sea -> bind ('<Double-1>' , \&LocateStrings ) ; -$fil -> bind ('<Double-1>' , \&LocateStrings ) ; -$loc -> bind ('<Double-1>' , \&ChangeLocation ) ; -$log -> bind ('<Double-1>' , \&ShowPath ) ; - -sub ChangePath - { my $currentpath = shift ; -chdir($currentpath) ; - $QuitSearch = 1 ; - $log -> delete ('1.0', 'end') ; - $log -> insert ('end', "$currentpath\n\n", 'title') } - -sub ChangeLocation - { $QuitSearch = 1 ; - $log -> delete ('1.0', 'end') ; - $Location =~ s/^\s*//o ; - $Location =~ s/\s*$//o ; - $Location =~ s/(\\|\/\/)/\//go ; - unless (-d $Location) - { unless ($Location =~ /\//) { $Location .= '/' } } - if (-d $Location) - { $log -> insert ('end', "changed to location '$Location'\n\n", 'title') ; - $currentpath = $Location ; - chdir ($currentpath) ; - $dir -> destroy ; - BuildDir ; - $dw -> raise ; - $dw -> focusForce } - else - { $log -> insert ('end', "unknown location '$Location'\n\n", 'title') ; - $Location = '' } } - -sub QuitSearch - { $QuitSearch = 1 } - -sub SearchFile - { my ($FileName, $SearchString) = @_ ; - my $Ok = 0 ; my $len ; - open (TEX, $FileName) ; - my $LineNumber = 0 ; - while (<TEX>) - { ++$LineNumber ; - if ($QuitSearch) - { if ($Ok) { $log -> see ('end') } - last } - if (/$SearchString/i) - { ++$NumberOfHits ; $num -> update ; - unless ($Ok) - { $Ok = 1 ; - $log -> insert ('end', "$FileName\n\n",'title') } - $log -> insert ('end', sprintf("%5i : ",$LineNumber), 'title') ; - s/^\s*//o ; -# - $len = 0 ; - while (/(.*?)($SearchString)/gi) - { $len += length($1) + length($2) ; - $log -> insert ('end', "$1") ; - $log -> insert ('end', "$2", 'found' ) } - $_ = substr($_,$len) ; - $log -> insert ('end', "$_") ; -# - $log -> update ; - $log -> see ('end') } } - if ($Ok) { $log -> insert ('end', "\n") } - close (TEX) } - -sub DoLocateFiles - { @FileList = () ; - $NumberOfHits = 0 ; - if ($FileSuffix ne "") - { $log -> delete ('1.0', 'end') ; - if ($Recurse) - { $log -> insert ('end', "recursively identifying files\n", 'title') ; - $log -> see ('end') ; - find (\&wanted, $currentpath) ; - sub wanted - { if ($QuitSearch) { last ; return } - if (/.*\.$FileSuffix/i) - { ++$NumberOfHits ; $num -> update ; - push @FileList, $File::Find::name } } } - else - { $log -> insert ('end', "identifying files\n", 'title') ; - $log -> see ('end') ; - opendir(DIR, $currentpath) ; my @TEMPLIST = readdir(DIR) ; closedir(DIR) ; - foreach my $FileName (@TEMPLIST) - { if ($FileName =~ /.*\.$FileSuffix/i) - { ++$NumberOfHits ; $num -> update ; - if ($QuitSearch) - { last } - push @FileList, $FileName } } } - @FileList = sort @FileList } } - -sub DoLocateStrings - { $log -> delete ('1.0', 'end') ; - $log -> update ; - $log -> see ('end') ; - $NumberOfHits = 0 ; - if ($SearchString ne "") - { foreach my $FileName (@FileList) - { if ($QuitSearch) - { $log -> insert ('end', "search aborted\n", 'title') ; - $log -> see ('end') ; - last } - SearchFile($FileName,$SearchString) } } - unless ($QuitSearch) - { $log -> insert ('end', "done\n", 'title') ; - $log -> see ('end') } } - -sub LocateStrings - { $QuitSearch = 0 ; - DoLocateFiles() ; - DoLocateStrings() } - -$log -> insert ('end', - - "data fields\n\n" , '' , - - - "string :", 'title', " regular expression to search for\n" , '' , - "suffix :", 'title', " type of file to search in\n" , '' , - "recurse :", 'title', " enable searching subpaths\n" , '' , - "location :", 'title', " drive of root path\n" , '' , - "counter :", 'title', " file/hit counter\n\n" , '' , - - "key bindings\n\n" , '' , - - "double 1 :", 'title', " directory window <-> search window\n" , '' , - "enter :", 'title', " start searching\n" , '' , - "escape :", 'title', " quit searching\n\n" , '' , - - "current path\n\n" , '' , - - cwd(), 'title', "\n\n" , 'title' ) ; - -$log -> update ; - -ShowPath ; - -MainLoop() ; diff --git a/scripts/context/perl/texfont.pl b/scripts/context/perl/texfont.pl deleted file mode 100644 index 5b3c1f1d7..000000000 --- a/scripts/context/perl/texfont.pl +++ /dev/null @@ -1,1373 +0,0 @@ -eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q' - if 0; - -# This is an example of a crappy unstructured file but once -# I know what should happen exactly, I will clean it up. - -# once it works all right, afmpl will be default - -# todo : ttf (partially doen already) - -# added: $pattern in order to avoid fuzzy shelle expansion of -# filenames (not consistent over perl and shells); i hate that -# kind of out of control features. - -#D \module -#D [ file=texfont.pl, -#D version=2004.02.06, % 2000.12.14 -#D title=Font Handling, -#D subtitle=installing and generating, -#D author=Hans Hagen ++, -#D date=\currentdate, -#D copyright={PRAGMA / Hans Hagen \& Ton Otten}] -#C -#C This module is part of the \CONTEXT\ macro||package and is -#C therefore copyrighted by \PRAGMA. See licen-en.pdf for -#C details. - -#D For usage information, see \type {mfonts.pdf}. - -#D Todo : copy afm/pfb from main to local files to ensure metrics -#D Todo : Wybo's help system -#D Todo : list of encodings [texnansi, ec, textext] - -#D Thanks to George N. White III for solving a couple of bugs. -#D Thanks to Adam T. Lindsay for adding Open Type support (and more). - -use strict ; - -my $savedoptions = join (" ",@ARGV) ; - -use Config ; -use FindBin ; -use File::Copy ; -use Getopt::Long ; -use Data::Dumper; - -$Getopt::Long::passthrough = 1 ; # no error message -$Getopt::Long::autoabbrev = 1 ; # partial switch accepted - -# Unless a user has specified an installation path, we take -# the dedicated font path or the local path. - -## $dosish = ($Config{'osname'} =~ /dos|mswin/i) ; -my $dosish = ($Config{'osname'} =~ /^(ms)?dos|^os\/2|^(ms|cyg)win/i) ; - -my $IsWin32 = ($^O =~ /MSWin32/i); -my $SpacyPath = 0 ; - -# great, the win32api is not present in all perls - -BEGIN { - $IsWin32 = ($^O =~ /MSWin32/i) ; - $SpacyPath = 0 ; - if ($IsWin32) { - my $str = `kpsewhich -expand-path=\$TEXMF` ; - $SpacyPath = ($str =~ / /) ; - if ($SpacyPath) { - require Win32::API; import Win32::API; - } - } -} - -# great, glob changed to bsd glob in an incompatible way ... sigh, we now -# have to catch a failed glob returning the pattern -# -# to stupid either: -# -# sub validglob { -# my @globbed = glob(shift) ; -# if ((@globbed) && (! -e $globbed[0])) { -# return () ; -# } else { -# return @globbed ; -# } -# } -# -# so now we have: - -sub validglob { - my @globbed = glob(shift) ; - my @globout = () ; - foreach my $file (@globbed) { - push (@globout,$file) if (-e $file) ; - } - return @globout ; -} - -sub GetShortPathName { - my ($filename) = @_ ; - return $filename unless (($IsWin32)&&($SpacyPath)) ; - my $GetShortPathName = new Win32::API('kernel32', 'GetShortPathName', 'PPN', 'N') ; - if(not defined $GetShortPathName) { - die "Can't import API GetShortPathName: $!\n" ; - } - my $buffer = " " x 260; - my $len = $GetShortPathName->Call($filename, $buffer, 260) ; - return substr($buffer, 0, $len) ; -} - -my $installpath = "" ; - -if (defined($ENV{TEXMFLOCAL})) { - $installpath = "TEXMFLOCAL" ; -} - -if (defined($ENV{TEXMFFONTS})) { - $installpath = "TEXMFFONTS" ; -} - -if ($installpath eq "") { - $installpath = "TEXMFLOCAL" ; # redundant -} - -my $encoding = "texnansi" ; -my $vendor = "" ; -my $collection = "" ; -my $fontroot = "" ; #/usr/people/gwhite/texmf-fonts" ; -my $help = 0 ; -my $makepath = 0 ; -my $show = 0 ; -my $install = 0 ; -my $sourcepath = "." ; -my $passon = "" ; -my $extend = "" ; -my $narrow = "" ; -my $slant = "" ; -my $spaced = "" ; -my $caps = "" ; -my $noligs = 0 ; -my $nofligs = 0 ; -my $test = 0 ; -my $virtual = 0 ; -my $novirtual = 0 ; -my $listing = 0 ; -my $remove = 0 ; -my $expert = 0 ; -my $trace = 0 ; -my $afmpl = 0 ; -my $trees = 'TEXMFFONTS,TEXMFLOCAL,TEXMFEXTRA,TEXMFMAIN,TEXMFDIST' ; -my $pattern = '' ; -my $uselmencodings = 0 ; - -my $fontsuffix = "" ; -my $namesuffix = "" ; - -my $batch = "" ; - -my $weight = "" ; -my $width = "" ; - -my $preproc = 0 ; # atl: formerly OpenType switch -my $variant = "" ; # atl: encoding variant -my $extension = "pfb" ; # atl: default font extension -my $lcdf = "" ; # atl: trigger for lcdf otftotfm - -my @cleanup = () ; # atl: build list of generated files to delete - -# todo: parse name for style, take face from command line -# -# @Faces = ("Serif","Sans","Mono") ; -# @Styles = ("Slanted","Spaced", "Italic","Bold","BoldSlanted","BoldItalic") ; -# -# for $fac (@Faces) { for $sty (@Styles) { $FacSty{"$fac$sty"} = "" } } - -&GetOptions - ( "help" => \$help, - "makepath" => \$makepath, - "noligs" => \$noligs, - "nofligs" => \$nofligs, - "show" => \$show, - "install" => \$install, - "encoding=s" => \$encoding, - "variant=s" => \$variant, # atl: used as a suffix to $encfile only - "vendor=s" => \$vendor, - "collection=s" => \$collection, - "fontroot=s" => \$fontroot, - "sourcepath=s" => \$sourcepath, - "passon=s" => \$passon, - "slant=s" => \$slant, - "spaced=s" => \$spaced, - "extend=s" => \$extend, - "narrow=s" => \$narrow, - "listing" => \$listing, - "remove" => \$remove, - "test" => \$test, - "virtual" => \$virtual, - "novirtual" => \$novirtual, - "caps=s" => \$caps, - "batch" => \$batch, - "weight=s" => \$weight, - "width=s" => \$width, - "expert" => \$expert, - "afmpl" => \$afmpl, - "afm2pl" => \$afmpl, - "lm" => \$uselmencodings, - "rootlist=s" => \$trees, - "pattern=s" => \$pattern, - "trace" => \$trace, # --verbose conflicts with --ve - "preproc" => \$preproc, # atl: trigger conversion to pfb - "lcdf" => \$lcdf ) ; # atl: trigger use of lcdf fonttoools - -# for/from Fabrice: - -my $own_path = "$FindBin::Bin/" ; - -$FindBin::RealScript =~ m/([^\.]*)(\.pl|\.bat|\.exe|)/io ; - -my $own_name = $1 ; -my $own_type = $2 ; -my $own_stub = "" ; - -if ($own_type =~ /pl/oi) { - $own_stub = "perl " -} - -if ($caps) { $afmpl = 0 } # for the moment - -# so we can use both combined - -if ($lcdf) { - $novirtual = 1 ; -} - -if (!$novirtual) { - $virtual = 1 ; -} - -# A couple of routines. - -sub report { - my $str = shift ; - $str =~ s/ / /goi ; - if ($str =~ /(.*?)\s+([\:\/])\s+(.*)/o) { - if ($1 eq "") { - $str = " " ; - } else { - $str = $2 ; - } - print sprintf("%22s $str %s\n",$1,$3) ; - } -} - -sub error { - report("processing aborted : " . shift) ; - print "\n" ; - report "--help : show some more info" ; - exit ; -} - -# The banner. - -print "\n" ; -report ("TeXFont 2.2.1 - ConTeXt / PRAGMA ADE 2000-2004") ; -print "\n" ; - -# Handy for scripts: one can provide a preferred path, if it -# does not exist, the current path is taken. - -if (!(-d $sourcepath)&&($sourcepath ne 'auto')) { $sourcepath = "." } - -# Let's make multiple masters if requested. - -sub create_mm_font - { my ($name,$weight,$width) = @_ ; my $flag = my $args = my $tags = "" ; - my $ok ; - if ($name ne "") - { report ("mm source file : $name") } - else - { error ("missing mm source file") } - if ($weight ne "") - { report ("weight : $weight") ; - $flag .= " --weight=$weight " ; - $tags .= "-weight-$weight" } - if ($width ne "") - { report ("width : $width") ; - $flag .= " --width=$width " ; - $tags .= "-width-$width" } - error ("no specification given") if ($tags eq "") ; - error ("no amfm file found") unless (-f "$sourcepath/$name.amfm") ; - error ("no pfb file found") unless (-f "$sourcepath/$name.pfb") ; - $args = "$flag --precision=5 --kern-precision=0 --output=$sourcepath/$name$tags.afm" ; - my $command = "mmafm $args $sourcepath/$name.amfm" ; - print "$command\n" if $trace ; - $ok = `$command` ; chomp $ok ; - if ($ok ne "") { report ("warning $ok") } - $args = "$flag --precision=5 --output=$sourcepath/$name$tags.pfb" ; - $command = "mmpfb $args $sourcepath/$name.pfb" ; - print "$command\n" if $trace ; - $ok = `$command` ; chomp $ok ; - if ($ok ne "") { report ("warning $ok") } - report ("mm result file : $name$tags") } - -if (($weight ne "")||($width ne "")) - { create_mm_font($ARGV[0],$weight,$width) ; - exit } - -# go on - -if (($listing||$remove)&&($sourcepath eq ".")) - { $sourcepath = "auto" } - -if ($fontroot eq "") - { if ($dosish) - { $fontroot = `kpsewhich -expand-path=\$$installpath` } - else - { $fontroot = `kpsewhich -expand-path=\\\$$installpath` } - chomp $fontroot } - - -if ($fontroot =~ /\s+/) # needed for windows, spaces in name - { $fontroot = &GetShortPathName($fontroot) } # but ugly when not needed - -if ($test) - { $vendor = $collection = "test" ; - $install = 1 } - -if (($spaced ne "") && ($spaced !~ /\d/)) { $spaced = "50" } -if (($slant ne "") && ($slant !~ /\d/)) { $slant = "0.167" } -if (($extend ne "") && ($extend !~ /\d/)) { $extend = "1.200" } -if (($narrow ne "") && ($narrow !~ /\d/)) { $narrow = "0.800" } -if (($caps ne "") && ($caps !~ /\d/)) { $caps = "0.800" } - -$encoding = lc $encoding ; -$vendor = lc $vendor ; -$collection = lc $collection ; - -if ($encoding =~ /default/oi) { $encoding = "texnansi" } - -my $lcfontroot = lc $fontroot ; - -# Auto search paths - -my @trees = split(/\,/,$trees) ; - -# Test for help asked. - -if ($help) - { report "--fontroot=path : texmf destination font root (default: $lcfontroot)" ; - report "--rootlist=paths : texmf source roots (default: $trees)" ; - report "--sourcepath=path : when installing, copy from this path (default: $sourcepath)" ; - report "--sourcepath=auto : locate and use vendor/collection" ; - print "\n" ; - report "--vendor=name : vendor name/directory" ; - report "--collection=name : font collection" ; - report "--encoding=name : encoding vector (default: $encoding)" ; - report "--variant=name : encoding variant (.enc file or otftotfm features)" ; - print "\n" ; - report "--spaced=s : space glyphs in font by promille of em (0 - 1000)" ; - report "--slant=s : slant glyphs in font by factor (0.0 - 1.5)" ; - report "--extend=s : extend glyphs in font by factor (0.0 - 1.5)" ; - report "--caps=s : capitalize lowercase chars by factor (0.5 - 1.0)" ; - report "--noligs --nofligs : remove ligatures" ; - print "\n" ; - report "--install : copy files from source to font tree" ; - report "--listing : list files on auto sourcepath" ; - report "--remove : remove files on auto sourcepath" ; - report "--makepath : when needed, create the paths" ; - print "\n" ; - report "--test : use test paths for vendor/collection" ; - report "--show : run tex on texfont.tex" ; - print "\n" ; - report "--batch : process given batch file" ; - print "\n" ; - report "--weight : multiple master weight" ; - report "--width : multiple master width" ; - print "\n" ; - report "--expert : also handle expert fonts" ; - print "\n" ; - report "--afmpl : use afm2pl instead of afm2tfm" ; - report "--preproc : pre-process ttf/otf, converting them to pfb" ; - report "--lcdf : use lcdf fonttools to create virtual encoding" ; - exit } - -if (($batch)||(($ARGV[0]) && ($ARGV[0] =~ /.+\.dat$/io))) - { my $batchfile = $ARGV[0] ; - unless (-f $batchfile) - { if ($batchfile !~ /\.dat$/io) { $batchfile .= ".dat" } } - unless (-f $batchfile) - { report ("trying to locate : $batchfile") ; - $batchfile = `kpsewhich -format="other text files" -progname=context $batchfile` ; - chomp $batchfile } - error ("unknown batch file $batchfile") unless -e $batchfile ; - report ("processing batch file : $batchfile") ; - my $select = (($vendor ne "")||($collection ne "")) ; - my $selecting = 0 ; - if (open(BAT, $batchfile)) - { while (<BAT>) - { chomp ; - s/(.+)\#.*/$1/o ; - next if (/^\s*$/io) ; - if ($select) - { if ($selecting) - { if (/^\s*[\#\%]/io) { if (!/\-\-/o) { last } else { next } } } - elsif ((/^\s*[\#\%]/io)&&(/$vendor/i)&&(/$collection/i)) - { $selecting = 1 ; next } - else - { next } } - else - { next if (/^\s*[\#\%]/io) ; - next unless (/\-\-/oi) } - s/\s+/ /gio ; - s/(--en.*\=)\?/$1$encoding/io ; - report ("batch line : $_") ; - # system ("perl $0 --fontroot=$fontroot $_") } - my $own_quote = ( $own_path =~ m/^[^\"].* / ? "\"" : "" ); - my $switches = '' ; - $switches .= "--afmpl " if $afmpl ; - system ("$own_stub$own_quote$own_path$own_name$own_type$own_quote $switches --fontroot=$fontroot $_") } - close (BAT) } - exit } - -error ("unknown vendor $vendor") unless $vendor ; -error ("unknown collection $collection") unless $collection ; -error ("unknown tex root $lcfontroot") unless -d $fontroot ; - -my $varlabel = $variant ; - -if ($lcdf) - { $varlabel =~ s/,/-/goi ; - $varlabel =~ tr/a-z/A-Z/ } - -if ($varlabel ne "") - { $varlabel = "-$varlabel" } - -my $identifier = "$encoding$varlabel-$vendor-$collection" ; - -my $outlinepath = $sourcepath ; my $path = "" ; - -my $shape = "" ; - -if ($noligs||$nofligs) - { report ("ligatures : removed") ; - $fontsuffix .= "-unligatured" ; - $namesuffix .= "-NoLigs" } - -if ($caps ne "") - { if ($caps <0.5) { $caps = 0.5 } - elsif ($caps >1.0) { $caps = 1.0 } - $shape .= " -c $caps " ; - report ("caps factor : $caps") ; - $fontsuffix .= "-capitalized-" . int(1000*$caps) ; - $namesuffix .= "-Caps" } - -if ($extend ne "") - { if ($extend<0.0) { $extend = 0.0 } - elsif ($extend>1.5) { $extend = 1.5 } - report ("extend factor : $extend") ; - if ($lcdf) - { $shape .= " -E $extend " } - else - { $shape .= " -e $extend " } - $fontsuffix .= "-extended-" . int(1000*$extend) ; - $namesuffix .= "-Extended" } - -if ($narrow ne "") # goodie - { $extend = $narrow ; - if ($extend<0.0) { $extend = 0.0 } - elsif ($extend>1.5) { $extend = 1.5 } - report ("narrow factor : $extend") ; - if ($lcdf) - { $shape .= " -E $extend " } - else - { $shape .= " -e $extend " } - $fontsuffix .= "-narrowed-" . int(1000*$extend) ; - $namesuffix .= "-Narrowed" } - -if ($slant ne "") - { if ($slant <0.0) { $slant = 0.0 } - elsif ($slant >1.5) { $slant = 1.5 } - report ("slant factor : $slant") ; - if ($lcdf) - { $shape .= " -S $slant " } - else - { $shape .= " -s $slant " } - $fontsuffix .= "-slanted-" . int(1000*$slant) ; - $namesuffix .= "-Slanted" } - -if ($spaced ne "") - { if ($spaced < 0) { $spaced = 0 } - elsif ($spaced >1000) { $spaced = 1000 } - report ("space factor : $spaced") ; - if ($lcdf) - { $shape .= " -L $spaced " } - else - { $shape .= " -m $spaced " } - $fontsuffix .= "-spaced-" . $spaced ; - $namesuffix .= "-Spaced" } - -if ($sourcepath eq "auto") # todo uppercase root - { foreach my $root (@trees) - { if ($dosish) - { $path = `kpsewhich -expand-path=\$$root` } - else - { $path = `kpsewhich -expand-path=\\\$$root` } - chomp $path ; - $path = $ENV{$root} if (($path eq '') && defined($ENV{$root})) ; - report ("checking root : $root") ; - if ($preproc) - { $sourcepath = "$path/fonts/truetype/$vendor/$collection" } - else - { $sourcepath = "$path/fonts/afm/$vendor/$collection" } - unless (-d $sourcepath) - { my $ven = $vendor ; $ven =~ s/(........).*/$1/ ; - my $col = $collection ; $col =~ s/(........).*/$1/ ; - $sourcepath = "$path/fonts/afm/$ven/$col" ; - if (-d $sourcepath) - { $vendor = $ven ; $collection = $col } } - $outlinepath = "$path/fonts/type1/$vendor/$collection" ; - if (-d $sourcepath) - { # $install = 0 ; # no copy needed - $makepath = 1 ; # make on local if needed - my @files = validglob("$sourcepath/*.afm") ; - if ($preproc) - { @files = validglob("$sourcepath/*.otf") ; - report("locating : otf files") } - unless (@files) - { @files = validglob("$sourcepath/*.ttf") ; - report("locating : ttf files") } - if (@files) - { if ($listing) - { report ("fontpath : $sourcepath" ) ; - print "\n" ; - foreach my $file (@files) - { if (open(AFM,$file)) - { my $name = "unknown name" ; - while (<AFM>) - { chomp ; - if (/^fontname\s+(.*?)$/oi) - { $name = $1 ; last } } - close (AFM) ; - if ($preproc) - { $file =~ s/.*\/(.*)\..tf/$1/io } - else - { $file =~ s/.*\/(.*)\.afm/$1/io } - report ("$file : $name") } } - exit } - elsif ($remove) - { error ("no removal from : $root") if ($root eq 'TEXMFMAIN') ; - foreach my $file (@files) - { if ($preproc) - { $file =~ s/.*\/(.*)\..tf/$1/io } - else - { $file =~ s/.*\/(.*)\.afm/$1/io } - foreach my $sub ("tfm","vf") - { foreach my $typ ("","-raw") - { my $nam = "$path/fonts/$sub/$vendor/$collection/$encoding$varlabel$typ-$file.$sub" ; - if (-s $nam) - { report ("removing : $encoding$varlabel$typ-$file.$sub") ; - unlink $nam } } } } - my $nam = "$encoding$varlabel-$vendor-$collection.tex" ; - if (-e $nam) - { report ("removing : $nam") ; - unlink "$nam" } - my $mapfile = "$encoding$varlabel-$vendor-$collection" ; - foreach my $map ("pdftex","dvips", "dvipdfm") - { my $maproot = "$fontroot/fonts/map/$map/context/"; - if (-e "$maproot$mapfile.map") - { report ("renaming : $mapfile.map -> $mapfile.bak") ; - unlink "$maproot$mapfile.bak" ; - rename "$maproot$mapfile.map", "$maproot$mapfile.bak" } } - exit } - else - { last } } } } - error ("unknown subpath ../fonts/afm/$vendor/$collection") unless -d $sourcepath } - -error ("unknown source path $sourcepath") unless -d $sourcepath ; -error ("unknown option $ARGV[0]") if (($ARGV[0]||'') =~ /\-\-/) ; - -my $afmpath = "$fontroot/fonts/afm/$vendor/$collection" ; -my $tfmpath = "$fontroot/fonts/tfm/$vendor/$collection" ; -my $vfpath = "$fontroot/fonts/vf/$vendor/$collection" ; -my $pfbpath = "$fontroot/fonts/type1/$vendor/$collection" ; -my $ttfpath = "$fontroot/fonts/truetype/$vendor/$collection" ; -my $otfpath = "$fontroot/fonts/opentype/$vendor/$collection" ; -my $encpath = "$fontroot/fonts/enc/dvips/context" ; - -sub mappath - { my $str = shift ; - return "$fontroot/fonts/map/$str/context" } - -# are not on local path ! ! ! ! - -foreach my $path ($afmpath, $pfbpath) - { my @gzipped = <$path/*.gz> ; - foreach my $file (@gzipped) - { print "file = $file\n"; - system ("gzip -d $file") } } - -# For gerben, we only generate a new database when an lsr file is present but for -# myself we force this when texmf-fonts is used (else I get compatibility problems). - -if (($fontroot =~ /texmf\-fonts/o) || (-e "$fontroot/ls-R") || (-e "$fontroot/ls-r") || (-e "$fontroot/LS-R")) { - system ("mktexlsr $fontroot") ; -} - -sub do_make_path - { my $str = shift ; - if ($str =~ /^(.*)\/.*?$/) - { do_make_path($1); } - mkdir $str, 0755 unless -d $str } - -sub make_path - { my $str = shift ; - do_make_path("$fontroot/fonts/$str/$vendor/$collection") } - -if ($makepath&&$install) - { make_path ("afm") ; make_path ("type1") } - -do_make_path(mappath("pdftex")) ; -do_make_path(mappath("dvips")) ; -do_make_path(mappath("dvipdfm")) ; -do_make_path($encpath) ; - -# now fonts/map and fonts/enc - -make_path ("vf") ; -make_path ("tfm") ; - -if ($install) - { error ("unknown afm path $afmpath") unless -d $afmpath ; - error ("unknown pfb path $pfbpath") unless -d $pfbpath } - -error ("unknown tfm path $tfmpath") unless -d $tfmpath ; -error ("unknown vf path $vfpath" ) unless -d $vfpath ; -error ("unknown map path " . mappath("pdftex")) unless -d mappath("pdftex"); -error ("unknown map path " . mappath("dvips")) unless -d mappath("dvips"); -error ("unknown map path " . mappath("dvipdfm")) unless -d mappath("dvipdfm"); - -my $mapfile = "$identifier.map" ; -my $bakfile = "$identifier.bak" ; -my $texfile = "$identifier.tex" ; - - report "encoding vector : $encoding" ; -if ($variant) { report "encoding variant : $variant" } - report "vendor name : $vendor" ; - report " source path : $sourcepath" ; - report "font collection : $collection" ; - report "texmf font root : $lcfontroot" ; - report " map file name : $mapfile" ; - -if ($install) { report "source path : $sourcepath" } - -my $fntlist = "" ; - -my $runpath = $sourcepath ; - -my @files ; - -sub UnLink - { foreach my $f (@_) - { if (unlink $f) - { report "deleted : $f" if $trace } } } - -sub globafmfiles - { my ($runpath, $pattern) = @_ ; - my @files = validglob("$runpath/$pattern.afm") ; - report("locating afm files : using pattern $runpath/$pattern.afm"); - if ($preproc && !$lcdf) - { @files = validglob("$runpath/$pattern.*tf") ; - report("locating otf files : using pattern $runpath/$pattern.*tf"); - unless (@files) - { @files = validglob("$sourcepath/$pattern.ttf") ; - report("locating ttf files : using pattern $sourcepath/$pattern.ttf") } - } - if (@files) # also elsewhere - { report("locating afm files : using pattern $pattern") } - else - { @files = validglob("$runpath/$pattern.ttf") ; - if (@files) - { report("locating afm files : using ttf files") ; - $extension = "ttf" ; - foreach my $file (@files) - { $file =~ s/\.ttf$//io ; - report ("generating afm file : $file.afm") ; - my $command = "ttf2afm \"$file.ttf\" -o \"$file.afm\"" ; - system($command) ; - print "$command\n" if $trace ; - push(@cleanup, "$file.afm") } - @files = validglob("$runpath/$pattern.afm") } - else # try doing the pre-processing earlier - { report("locating afm files : using otf files") ; - $extension = "otf" ; - @files = validglob("$runpath/$pattern.otf") ; - foreach my $file (@files) - { $file =~ s/\.otf$//io ; - if (!$lcdf) - { report ("generating afm file : $file.afm") ; - preprocess_font("$file.otf", "$file.bdf") ; - push(@cleanup,"$file.afm") } - if ($preproc) - { my $command = "cfftot1 --output=$file.pfb $file.otf" ; - print "$command\n" if $trace ; - report("converting : $file.otf to $file.pfb") ; - system($command) ; - push(@cleanup, "$file.pfb") ; - } - } - if ($lcdf) - { @files = validglob("$runpath/$pattern.otf") } - else - { @files = validglob("$runpath/$pattern.afm") } - } - } - return @files } - -if ($pattern eq '') { if ($ARGV[0]) { $pattern = $ARGV[0] } } - -if ($pattern ne '') - { report ("processing files : all in pattern $pattern") ; - @files = globafmfiles($runpath,$pattern) } -elsif ("$extend$narrow$slant$spaced$caps" ne "") - { error ("transformation needs file spec") } -else - { $pattern = "*" ; - report ("processing files : all on afm path") ; - @files = globafmfiles($runpath,$pattern) } - -sub copy_files - { my ($suffix,$sourcepath,$topath) = @_ ; - my @files = validglob("$sourcepath/$pattern.$suffix") ; - return if ($topath eq $sourcepath) ; - report ("copying files : $suffix") ; - foreach my $file (@files) - { my $ok = $file =~ /(.*)\/(.+?)\.(.*)/ ; - my ($path,$name,$suffix) = ($1,$2,$3) ; - UnLink "$topath/$name.$suffix" ; - report ("copying : $name.$suffix") ; - copy ($file,"$topath/$name.$suffix") } } - -if ($install) - { copy_files("afm",$sourcepath,$afmpath) ; -# copy_files("tfm",$sourcepath,$tfmpath) ; # raw supplied names - copy_files("pfb",$outlinepath,$pfbpath) ; - if ($extension eq "ttf") - { make_path("truetype") ; - copy_files("ttf",$sourcepath,$ttfpath) } - if ($extension eq "otf") - { make_path("truetype") ; - copy_files("otf",$sourcepath,$ttfpath) } } - -error ("no afm files found") unless @files ; - -sub open_mapfile - { my $type = shift; - my $mappath = mappath($type); - my $mapdata = ""; - my $mapptr = undef; - my $fullmapfile = $mapfile; - $fullmapfile = "$type-$fullmapfile" unless $type eq "pdftex"; - if ($install) - { copy ("$mappath/$mapfile","$mappath/$bakfile") ; } - if (open ($mapptr,"<$mappath/$mapfile")) - { report ("extending map file : $mappath/$mapfile") ; - while (<$mapptr>) { unless (/^\%/o) { $mapdata .= $_ } } - close ($mapptr) } - else - { report ("no map file at : $mappath/$mapfile") } - #~ unless (open ($mapptr,">$fullmapfile") ) -do_make_path($mappath) ; - unless (open ($mapptr,">$mappath/$fullmapfile") ) - { report "warning : can't open $fullmapfile" } - else - { if ($type eq "pdftex") - { print $mapptr "% This file is generated by the TeXFont Perl script.\n"; - print $mapptr "%\n" ; - print $mapptr "% You need to add the following line to your file:\n" ; - print $mapptr "%\n" ; - print $mapptr "% \\pdfmapfile{+$mapfile}\n" ; - print $mapptr "%\n" ; - print $mapptr "% In ConTeXt you can best use:\n" ; - print $mapptr "%\n" ; - print $mapptr "% \\loadmapfile\[$mapfile\]\n\n" } } - return ($mapptr,$mapdata) ; } - -sub finish_mapfile - { my ($type, $mapptr, $mapdata ) = @_; - my $fullmapfile = $mapfile; - $fullmapfile = "$type-$fullmapfile" unless $type eq "pdftex"; - if (defined $mapptr) - { report ("updating map file : $mapfile (for $type)") ; - while ($mapdata =~ s/\n\n+/\n/mois) {} ; - $mapdata =~ s/^\s*//gmois ; - print $mapptr $mapdata ; - close ($mapptr) ; - if ($install) - { copy ("$fullmapfile", mappath($type) . "/$mapfile") ; } } } - - -my ($PDFTEXMAP,$pdftexmapdata) = open_mapfile("pdftex"); -my ($DVIPSMAP,$dvipsmapdata) = open_mapfile("dvips"); -my ($DVIPDFMMAP,$dvipdfmmapdata) = open_mapfile("dvipdfm"); - -my $tex = 0 ; -my $texdata = "" ; - -if (open (TEX,"<$texfile")) - { while (<TEX>) { unless (/stoptext/o) { $texdata .= $_ } } - close (TEX) } - -$tex = open (TEX,">$texfile") ; - -unless ($tex) { report "warning : can't open $texfile" } - -if ($tex) - { if ($texdata eq "") - { print TEX "% interface=en\n" ; - print TEX "\n" ; - print TEX "\\usemodule[fnt-01]\n" ; - print TEX "\n" ; - print TEX "\\loadmapfile[$mapfile]\n" ; - print TEX "\n" ; - print TEX "\\starttext\n\n" } - else - { print TEX "$texdata" ; - print TEX "\n\%appended section\n\n\\page\n\n" } } - -sub removeligatures - { my $filename = shift ; my $skip = 0 ; - copy ("$filename.vpl","$filename.tmp") ; - if ((open(TMP,"<$filename.tmp"))&&(open(VPL,">$filename.vpl"))) - { report "removing ligatures : $filename" ; - while (<TMP>) - { chomp ; - if ($skip) - { if (/^\s*\)\s*$/o) { $skip = 0 ; print VPL "$_\n" } } - elsif (/\(LIGTABLE/o) - { $skip = 1 ; print VPL "$_\n" } - else - { print VPL "$_\n" } } - close(TMP) ; close(VPL) } - UnLink ("$filename.tmp") } - -my $raw = my $use = my $maplist = my $texlist = my $report = "" ; - -$use = "$encoding$varlabel-" ; $raw = $use . "raw-" ; - -my $encfil = "" ; - -if ($encoding ne "") # evt -progname=context - { $encfil = `kpsewhich -progname=pdftex $encoding$varlabel.enc` ; - chomp $encfil ; if ($encfil eq "") { $encfil = "$encoding$varlabel.enc" } } - -sub build_pdftex_mapline - { my ($option, $usename, $fontname, $rawname, $cleanfont, $encoding, $varlabel, $strange) = @_; - my $cleanname = $fontname; - $cleanname =~ s/\_//gio ; - $option =~ s/^\s+(.*)/$1/o ; - $option =~ s/(.*)\s+$/$1/o ; - $option =~ s/ / /g ; - if ($option ne "") - { $option = "\"$option\" 4" } - else - { $option = "4" } - # adding cleanfont is kind of dangerous - my $thename = ""; - my $str = ""; - my $theencoding = "" ; - if ($strange ne "") - { $thename = $cleanname ; $theencoding = "" ; } - elsif ($lcdf) - { $thename = $usename ; $theencoding = " $encoding$varlabel-$cleanname.enc" } - elsif ($afmpl) - { $thename = $usename ; $theencoding = " $encoding$varlabel.enc" } - elsif ($virtual) - { $thename = $rawname ; $theencoding = " $encoding$varlabel.enc" } - else - { $thename = $usename ; $theencoding = " $encoding$varlabel.enc" } -if ($uselmencodings) { - $theencoding =~ s/^(ec)\.enc/lm\-$1.enc/ ; -} - # quit rest if no type 1 file - my $pfb_sourcepath = $sourcepath ; - $pfb_sourcepath =~ s@/afm/@/type1/@ ; - unless ((-e "$pfbpath/$fontname.$extension")|| - (-e "$pfb_sourcepath/$fontname.$extension")|| - (-e "$sourcepath/$fontname.$extension")|| - (-e "$ttfpath/$fontname.$extension")) - { if ($tex) { $report .= "missing file: \\type \{$fontname.pfb\}\n" } - report ("missing pfb file : $fontname.pfb") } - # now add entry to map - if ($strange eq "") { - if ($extension eq "otf") { - if ($lcdf) { - my $mapline = "" ; - if (open(ALTMAP,"texfont.map")) { - while (<ALTMAP>) { - chomp ; - # atl: we assume this b/c we always force otftotfm --no-type1 - if (/<<(.*)\.otf$/oi) { - $mapline = $_ ; last ; - } - } - close(ALTMAP) ; - } else { - report("no mapfile from otftotfm : texfont.map") ; - } - if ($preproc) { - $mapline =~ s/<\[/</; - $mapline =~ s/<<(\S+)\.otf$/<$1\.pfb/ ; - } else { - $mapline =~ s/<<(\S+)\.otf$/<< $ttfpath\/$fontname.$extension/ ; - } - $str = "$mapline\n" ; - } else { - if ($preproc) { - $str = "$thename $cleanfont $option < $fontname.pfb$theencoding\n" ; - } else { - # PdfTeX can't subset OTF files, so we have to include the whole thing - # It looks like we also need to be explicit on where to find the file - $str = "$thename $cleanfont $option << $ttfpath/$fontname.$extension <$theencoding\n" ; - } - } - } else { - $str = "$thename $cleanfont $option < $fontname.$extension$theencoding\n" ; - } - } else { - $str = "$thename $cleanfont < $fontname.$extension\n" ; - } - return ($str, $thename); } - -sub build_dvips_mapline - { my ($option, $usename, $fontname, $rawname, $cleanfont, $encoding, $varlabel, $strange) = @_; - my $cleanname = $fontname; - $cleanname =~ s/\_//gio ; - $option =~ s/^\s+(.*)/$1/o ; - $option =~ s/(.*)\s+$/$1/o ; - $option =~ s/ / /g ; - # adding cleanfont is kind of dangerous - my $thename = ""; - my $str = ""; - my $optionencoding = "" ; - my $encname = ""; - my $theencoding = "" ; - if ($encoding ne "") # evt -progname=context - { $encfil = `kpsewhich -progname=dvips $encoding$varlabel.enc` ; - chomp $encfil ; - if ($encfil eq "") - { $encfil = "$encoding$varlabel.enc" ; } - if (open(ENC,"<$encfil")) - { while (<ENC>) - { if (/^\/([^ ]+)\s*\[/) - { $encname = $1; - last; } } - close ENC; } } - if ($strange ne "") - { $thename = $cleanname ; - $optionencoding = "\"$option\"" if length($option)>1; } - elsif ($lcdf) - { $thename = $usename ; - $optionencoding = "\"$option $encname ReEncodeFont\" <$encoding$varlabel-$cleanname.enc" } - elsif ($afmpl) - { $thename = $usename ; - $optionencoding = "\"$option $encname ReEncodeFont\" <$encoding$varlabel.enc" } - elsif ($virtual) - { $thename = $rawname ; - $optionencoding = "\"$option $encname ReEncodeFont\" <$encoding$varlabel.enc" } - else - { $thename = $usename ; - $optionencoding = "\"$option $encname ReEncodeFont\" <$encoding$varlabel.enc" } -if ($uselmencodings) { - $theencoding =~ s/^(ec)\.enc/lm\-$1.enc/ ; -} - # quit rest if no type 1 file - my $pfb_sourcepath = $sourcepath ; - $pfb_sourcepath =~ s@/afm/@/type1/@ ; - unless ((-e "$pfbpath/$fontname.$extension")|| - (-e "$pfb_sourcepath/$fontname.$extension")|| - (-e "$sourcepath/$fontname.$extension")|| - (-e "$ttfpath/$fontname.$extension")) - { if ($tex) { $report .= "missing file: \\type \{$fontname.pfb\}\n" } - report ("missing pfb file : $fontname.pfb") } - # now add entry to map - if ($strange eq "") { - if ($extension eq "otf") { - if ($lcdf) { - my $mapline = "" ; - if (open(ALTMAP,"texfont.map")) { - while (<ALTMAP>) { - chomp ; - # atl: we assume this b/c we always force otftotfm --no-type1 - if (/<<(.*)\.otf$/oi) { - $mapline = $_ ; last ; - } - } - close(ALTMAP) ; - } else { - report("no mapfile from otftotfm : texfont.map") ; - } - if ($preproc) { - $mapline =~ s/<\[/</; - $mapline =~ s/<<(\S+)\.otf$/<$1\.pfb/ ; - } else { - $mapline =~ s/<<(\S+)\.otf$/<< $ttfpath\/$fontname.$extension/ ; - } - $str = "$mapline\n" ; - } else { - if ($preproc) { - $str = "$thename $cleanfont $optionencoding <$fontname.pfb\n" ; - } else { - # dvips can't subset OTF files, so we have to include the whole thing - # It looks like we also need to be explicit on where to find the file - $str = "$thename $cleanfont $optionencoding << $ttfpath/$fontname.$extension \n" ; - } - } - } else { - $str = "$thename $cleanfont $optionencoding <$fontname.$extension\n" ; - } - } else { - $str = "$thename $cleanfont $optionencoding <$fontname.$extension\n" ; - } - return ($str, $thename); } -# return $str; } - - -sub build_dvipdfm_mapline - { my ($option, $usename, $fontname, $rawname, $cleanfont, $encoding, $varlabel, $strange) = @_; - my $cleanname = $fontname; - $cleanname =~ s/\_//gio ; - $option =~ s/([\d\.]+)\s+SlantFont/ -s $1 /; - $option =~ s/([\d\.]+)\s+ExtendFont/ -e $1 /; - $option =~ s/^\s+(.*)/$1/o ; - $option =~ s/(.*)\s+$/$1/o ; - $option =~ s/ / /g ; - # adding cleanfont is kind of dangerous - my $thename = ""; - my $str = ""; - my $theencoding = "" ; - if ($strange ne "") - { $thename = $cleanname ; $theencoding = "" ; } - elsif ($lcdf) - { $thename = $usename ; $theencoding = " $encoding$varlabel-$cleanname" } - elsif ($afmpl) - { $thename = $usename ; $theencoding = " $encoding$varlabel" } - elsif ($virtual) - { $thename = $rawname ; $theencoding = " $encoding$varlabel" } - else - { $thename = $usename ; $theencoding = " $encoding$varlabel" } -if ($uselmencodings) { - $theencoding =~ s/^(ec)\.enc/lm\-$1.enc/ ; -} - # quit rest if no type 1 file - my $pfb_sourcepath = $sourcepath ; - $pfb_sourcepath =~ s@/afm/@/type1/@ ; - unless ((-e "$pfbpath/$fontname.$extension")|| - (-e "$pfb_sourcepath/$fontname.$extension")|| - (-e "$sourcepath/$fontname.$extension")|| - (-e "$ttfpath/$fontname.$extension")) - { if ($tex) { $report .= "missing file: \\type \{$fontname.pfb\}\n" } - report ("missing pfb file : $fontname.pfb") } - # now add entry to map - if ($strange eq "") { - if ($extension eq "otf") { - #TH: todo - } else { - $str = "$thename $theencoding $fontname $option\n" ; - } - } else { - $str = "$thename $fontname $option\n" ; - } - return ($str, $thename); } -# return $str; } - - -sub preprocess_font - { my ($infont,$pfbfont) = @_ ; - if ($infont ne "") - { report ("otf/ttf source file : $infont") ; - report ("destination file : $pfbfont") ; } - else - { error ("missing otf/ttf source file") } - open (CONVERT, "| pfaedit -script -") || error ("couldn't open pipe to pfaedit") ; - report ("pre-processing with : pfaedit") ; - print CONVERT "Open('$infont');\n Generate('$pfbfont', '', 1) ;\n" ; - close (CONVERT) } - -foreach my $file (@files) - { my $option = my $slant = my $spaced = my $extend = my $vfstr = my $encstr = "" ; - my $strange = "" ; my ($rawfont,$cleanfont,$restfont) ; - $file = $file ; - my $ok = $file =~ /(.*)\/(.+?)\.(.*)/ ; - my ($path,$name,$suffix) = ($1,$2,$3) ; - # remove trailing _'s - my $fontname = $name ; - my $cleanname = $fontname ; - $cleanname =~ s/\_//gio ; - # atl: pre-process an opentype or truetype file by converting to pfb - if ($preproc && !$lcdf) - { unless (-f "$afmpath/$cleanname.afm" && -f "$pfbpath/$cleanname.pfb") - { preprocess_font("$path/$name.$suffix", "$pfbpath/$cleanname.pfb") ; - rename("$pfbpath/$cleanname.afm", "$afmpath/$cleanname.afm") - || error("couldn't move afm product of pre-process.") } - $path = $afmpath ; - $file = "$afmpath/$cleanname.afm" } - # cleanup - foreach my $suf ("tfm", "vf", "vpl") - { UnLink "$raw$cleanname$fontsuffix.$suf" ; - UnLink "$use$cleanname$fontsuffix.$suf" } - UnLink "texfont.log" ; - # set switches - if ($encoding ne "") - { $encstr = " -T $encfil" } - if ($caps ne "") - { $vfstr = " -V $use$cleanname$fontsuffix" } - else # if ($virtual) - { $vfstr = " -v $use$cleanname$fontsuffix" } - my $font = ""; - # let's see what we have here (we force texnansi.enc to avoid error messages) - if ($lcdf) - { my $command = "otfinfo -p $file" ; - print "$command\n" if $trace; - $font = `$command` ; - chomp $font ; - $cleanname = $cleanfont = $font } - else - { my $command = "afm2tfm \"$file\" -p texnansi.enc texfont.tfm" ; - print "$command (for testing)\n" if $trace ; - $font = `$command` ; - UnLink "texfont.tfm" ; - ($rawfont,$cleanfont,$restfont) = split(/\s/,$font) } - if ($font =~ /(math|expert)/io) { $strange = lc $1 } - $cleanfont =~ s/\_/\-/goi ; - $cleanfont =~ s/\-+$//goi ; - print "\n" ; - if (($strange eq "expert")&&($expert)) - { report ("font identifier : $cleanfont$namesuffix -> $strange -> tfm") } - elsif ($strange ne "") - { report ("font identifier : $cleanfont$namesuffix -> $strange -> skipping") } - elsif ($afmpl) - { report ("font identifier : $cleanfont$namesuffix -> text -> tfm") } - elsif ($virtual) - { report ("font identifier : $cleanfont$namesuffix -> text -> tfm + vf") } - else - { report ("font identifier : $cleanfont$namesuffix -> text -> tfm") } - # don't handle strange fonts - if ($strange eq "") - { # atl: support for lcdf otftotfm - if ($lcdf && $extension eq "otf") - { # no vf, bypass afm, use otftotfm to get encoding and tfm - my $varstr = my $encout = my $tfmout = "" ; - report "processing files : otf -> tfm + enc" ; - if ($encoding ne "") - { $encfil = `kpsewhich -progname=pdftex $encoding.enc` ; - chomp $encfil ; if ($encfil eq "") { $encfil = "$encoding.enc" } - $encstr = " -e $encfil " } - if ($variant ne "") - { ( $varstr = $variant ) =~ s/,/ -f /goi ; - $varstr = " -f $varstr" } - $encout = "$encpath/$use$cleanfont.enc" ; - if (-e $encout) - { report ("renaming : $encout -> $use$cleanfont.bak") ; - UnLink "$encpath/$use$cleanfont.bak" ; - rename $encout, "$encpath/$use$cleanfont.bak" } - UnLink "texfont.map" ; - $tfmout = "$use$cleanfont$fontsuffix" ; - my $otfcommand = "otftotfm -a $varstr $encstr $passon $shape --name=\"$tfmout\" --encoding-dir=\"$encpath/\" --tfm-dir=\"$tfmpath/\" --vf-dir=\"$vfpath/\" --no-type1 --map-file=./texfont.map \"$file\"" ; - print "$otfcommand\n" if $trace ; - system("$otfcommand") ; - $encfil = $encout } - else - { # generate tfm and vpl, $file is on afm path - my $font = '' ; - if ($afmpl) - { report " generating pl : $cleanname$fontsuffix (from $cleanname)" ; - $encstr = " -p $encfil" ; - if ($uselmencodings) { - $encstr =~ s/(ec)\.enc$/lm\-$1\.enc/ ; - } - my $command = "afm2pl -f afm2tfm $shape $passon $encstr $file $cleanname$fontsuffix.vpl" ; - print "$command\n" if $trace ; - my $ok = `$command` ; - if (open (TMP,"$cleanname$fontsuffix.map")) - { $font = <TMP> ; - close(TMP) ; - UnLink "$cleanname$fontsuffix.map" } } - else - { report "generating raw tfm/vpl : $raw$cleanname$fontsuffix (from $cleanname)" ; - my $command = "afm2tfm $file $shape $passon $encstr $vfstr $raw$cleanname$fontsuffix" ; - print "$command\n" if $trace ; - $font = `$command` } - # generate vf file if needed - chomp $font ; - if ($font =~ /.*?([\d\.]+)\s*ExtendFont/io) { $extend = $1 } - if ($font =~ /.*?([\d\.]+)\s*SlantFont/io) { $slant = $1 } - if ($extend ne "") { $option .= " $extend ExtendFont " } - if ($slant ne "") { $option .= " $slant SlantFont " } - if ($afmpl) - { if ($noligs||$nofligs) { removeligatures("$cleanname$fontsuffix") } - report "generating new tfm : $use$cleanname$fontsuffix" ; - my $command = "pltotf $cleanname$fontsuffix.vpl $use$cleanname$fontsuffix.tfm" ; - print "$command\n" if $trace ; - my $ok = `$command` } - elsif ($virtual) - { if ($noligs||$nofligs) { removeligatures("$use$cleanname$fontsuffix") } - report "generating new vf : $use$cleanname$fontsuffix (from $use$cleanname)" ; - my $command = "vptovf $use$cleanname$fontsuffix.vpl $use$cleanname$fontsuffix.vf $use$cleanname$fontsuffix.tfm" ; - print "$command\n" if $trace ; - my $ok = `$command` } - else - { if ($noligs||$nofligs) { removeligatures("$raw$cleanname$fontsuffix") } - report "generating new tfm : $use$cleanname$fontsuffix (from $raw$cleanname)" ; - my $command = "pltotf $raw$cleanname$fontsuffix.vpl $use$cleanname$fontsuffix.tfm" ; - print "$command\n" if $trace ; - my $ok = `$command` } } } - elsif (-e "$sourcepath/$cleanname.tfm" ) - { report "using existing tfm : $cleanname.tfm" } - elsif (($strange eq "expert")&&($expert)) - { report "creating tfm file : $cleanname.tfm" ; - my $command = "afm2tfm $file $cleanname.tfm" ; - print "$command\n" if $trace ; - my $font = `$command` } - else - { report "use supplied tfm : $cleanname" } - # report results - if (!$lcdf) - { ($rawfont,$cleanfont,$restfont) = split(/\s/,$font) } - $cleanfont =~ s/\_/\-/goi ; - $cleanfont =~ s/\-+$//goi ; - # copy files - my $usename = "$use$cleanname$fontsuffix" ; - my $rawname = "$raw$cleanname$fontsuffix" ; - - if ($lcdf eq "") - { if ($strange ne "") - { UnLink ("$vfpath/$cleanname.vf", "$tfmpath/$cleanname.tfm") ; - copy ("$cleanname.tfm","$tfmpath/$cleanname.tfm") ; - copy ("$usename.tfm","$tfmpath/$usename.tfm") ; - # or when available, use vendor one : - copy ("$sourcepath/$cleanname.tfm","$tfmpath/$cleanname.tfm") } - elsif ($virtual) - { UnLink ("$vfpath/$rawname.vf", "$vfpath/$usename.vf") ; - UnLink ("$tfmpath/$rawname.tfm", "$tfmpath/$usename.tfm") ; - copy ("$usename.vf" ,"$vfpath/$usename.vf") ; - copy ("$rawname.tfm","$tfmpath/$rawname.tfm") ; - copy ("$usename.tfm","$tfmpath/$usename.tfm") } - elsif ($afmpl) - { UnLink ("$vfpath/$rawname.vf", "$vfpath/$usename.vf", "$vfpath/$cleanname.vf") ; - UnLink ("$tfmpath/$rawname.tfm", "$tfmpath/$usename.tfm", "$tfmpath/$cleanname.tfm") ; - copy ("$usename.tfm","$tfmpath/$usename.tfm") } - else - { UnLink ("$vfpath/$usename.vf", "$tfmpath/$usename.tfm") ; - # slow but prevents conflicting vf's - my $rubish = `kpsewhich $usename.vf` ; chomp $rubish ; - if ($rubish ne "") { UnLink $rubish } - # - copy ("$usename.tfm","$tfmpath/$usename.tfm") } } - # cleanup - foreach my $suf ("tfm", "vf", "vpl") - { UnLink ("$rawname.$suf", "$usename.$suf") ; - UnLink ("$cleanname.$suf", "$fontname.$suf") ; - UnLink ("$cleanname$fontsuffix.$suf", "$fontname$fontsuffix.$suf") } - # add line to map files - my $str = my $thename = ""; - ($str, $thename) = build_pdftex_mapline($option, $usename, $fontname, $rawname, $cleanfont, $encoding, $varlabel, $strange); - # check for redundant entries - if (defined $PDFTEXMAP) { - $pdftexmapdata =~ s/^$thename\s.*?$//gmis ; - if ($afmpl) { - if ($pdftexmapdata =~ s/^$rawname\s.*?$//gmis) { - report ("removing raw file : $rawname") ; - } - } - $maplist .= $str ; - $pdftexmapdata .= $str ; - } - ($str, $thename) = build_dvips_mapline($option, $usename, $fontname, $rawname, $cleanfont, $encoding, $varlabel, $strange); - # check for redundant entries - if (defined $DVIPSMAP) { - $dvipsmapdata =~ s/^$thename\s.*?$//gmis ; - if ($afmpl) { - if ($dvipsmapdata =~ s/^$rawname\s.*?$//gmis) { - report ("removing raw file : $rawname") ; - } - } - $dvipsmapdata .= $str ; - } - ($str, $thename) = build_dvipdfm_mapline($option, $usename, $fontname, $rawname, $cleanfont, $encoding, $varlabel, $strange); - # check for redundant entries - if (defined $DVIPDFMMAP) { - $dvipdfmmapdata =~ s/^$thename\s.*?$//gmis ; - if ($afmpl) { - if ($dvipdfmmapdata =~ s/^$rawname\s.*?$//gmis) { - report ("removing raw file : $rawname") ; - } - } - $dvipdfmmapdata .= $str ; - } - - # write lines to tex file - if (($strange eq "expert")&&($expert)) { - $fntlist .= "\\definefontsynonym[$cleanfont$namesuffix][$cleanname] \% expert\n" ; - } elsif ($strange ne "") { - $fntlist .= "\%definefontsynonym[$cleanfont$namesuffix][$cleanname]\n" ; - } else { - $fntlist .= "\\definefontsynonym[$cleanfont$namesuffix][$usename][encoding=$encoding]\n" ; - } - next unless $tex ; - if (($strange eq "expert")&&($expert)) { - $texlist .= "\\ShowFont[$cleanfont$namesuffix][$cleanname]\n" ; - } elsif ($strange ne "") { - $texlist .= "\%ShowFont[$cleanfont$namesuffix][$cleanname]\n" ; - } else { - $texlist .= "\\ShowFont[$cleanfont$namesuffix][$usename][$encoding]\n" - } -} - -finish_mapfile("pdftex", $PDFTEXMAP, $pdftexmapdata); -finish_mapfile("dvipdfm", $DVIPDFMMAP, $dvipdfmmapdata); -finish_mapfile("dvips", $DVIPSMAP, $dvipsmapdata); - -if ($tex) - { my $mappath = mappath("pdftex"); - $mappath =~ s/\\/\//go ; - $savedoptions =~ s/^\s+//gmois ; $savedoptions =~ s/\s+$//gmois ; - $fntlist =~ s/^\s+//gmois ; $fntlist =~ s/\s+$//gmois ; - $maplist =~ s/^\s+//gmois ; $maplist =~ s/\s+$//gmois ; - print TEX "$texlist" ; - print TEX "\n" ; - print TEX "\\setupheadertexts[\\tttf example definitions]\n" ; - print TEX "\n" ; - print TEX "\\starttyping\n" ; - print TEX "texfont $savedoptions\n" ; - print TEX "\\stoptyping\n" ; - print TEX "\n" ; - print TEX "\\starttyping\n" ; - print TEX "$mappath/$mapfile\n" ; - print TEX "\\stoptyping\n" ; - print TEX "\n" ; - print TEX "\\starttyping\n" ; - print TEX "$fntlist\n" ; - print TEX "\\stoptyping\n" ; - print TEX "\n" ; - print TEX "\\page\n" ; - print TEX "\n" ; - print TEX "\\setupheadertexts[\\tttf $mapfile]\n" ; - print TEX "\n" ; - print TEX "\\starttyping\n" ; - print TEX "$maplist\n" ; - print TEX "\\stoptyping\n" ; - print TEX "\n" ; - print TEX "\\stoptext\n" } - -if ($tex) { close (TEX) } - -# atl: global cleanup with generated files (afm & ttf don't mix) - -UnLink(@cleanup) ; - -print "\n" ; report ("generating : ls-r databases") ; - -# Refresh database. - -print "\n" ; system ("mktexlsr $fontroot") ; print "\n" ; - -# Process the test file. - -if ($show) { system ("texexec --once --silent $texfile") } - -@files = validglob("$identifier.* *-$identifier.map") ; - -foreach my $file (@files) - { unless ($file =~ /(tex|pdf|log|mp|tmp)$/io) { UnLink ($file) } } - -exit ; diff --git a/scripts/context/perl/texutil.pl b/scripts/context/perl/texutil.pl deleted file mode 100644 index ca3645015..000000000 --- a/scripts/context/perl/texutil.pl +++ /dev/null @@ -1,2914 +0,0 @@ -eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q' - if 0; - -#D \module -#D [ file=texutil.pl, -#D version=2003.09.16, -#D title=pre- and postprocessing utilities, -#D subtitle=\TEXUTIL, -#D author=Hans Hagen, -#D date=\currentdate, -#D copyright={PRAGMA / Hans Hagen \& Ton Otten}] -#C -#C This module is part of the \CONTEXT\ macro||package and is -#C therefore copyrighted by \PRAGMA. See licen-en.pdf for -#C details. - -# much functionality will move to ctxtools, xmltools and pdftools; that way texutil -# becomes limited to tui processing only, which is cleaner (also for taco's binary -# version) - -# Thanks to Tobias Burnus for the german translations. -# Thanks to Thomas Esser for hooking it into web2c -# Thanks to Taco Hoekwater for making the file -w proof and some fixes -# Thanks to Alex Knowles and friends for the right JPG specs -# Thanks to Sebastian Rahtz for the eps to PDF method -# Thanks to Fabrice Popineau for windows bin code - -#D We started with a hack provided by Thomas Esser. This -#D expression replaces the unix specific line \type -#D {#!/usr/bin/perl}. - -# undocumented: -# -# --analyze file.pdf : reports some statistics -# --purge [jobname] : removes temporary files -# --purgeall [jobname] : removes all temporary files - -#D This is \TEXUTIL, a utility program (script) to be used -#D alongside the \CONTEXT\ macro package. This \PERL\ script is -#D derived from the \MODULA\ version and uses slightly better -#D algoritms for sanitizing \TEX\ specific (sub|)|strings. -#D -#D This implementation has some features not found in the -#D binary version, like scanning illustrations other than \EPS. -#D I would suggest to keep an eye on the version number: - -$Program = "TeXUtil 9.0.1 - ConTeXt / PRAGMA ADE 1992-2006" ; - -#D By the way, this is my first \PERL\ script, which means -#D that it will be improved as soon as I find new and/or more -#D suitable solutions in the \PERL\ manuals. As can be seen in -#D the definition of \type{$Program}, this program is part of -#D the \CONTEXT\ suite, and therefore can communicate with the -#D users in english as well as some other languages. One can -#D set his favourite language by saying something like: - -#D This one has a real old date, 1992. This is because it is -#D a converted modula program that was used in the very early -#D days of our \TEX\ history (macros for proper inclusion of -#D graphics were among the first thatwe wrote). - -#D \starttypen -#D perl texutil.pl --int=de --fig *.eps *.tif *.pdf *.png *.jpg -#D \stoptypen -#D -#D or simpler: -#D -#D \starttypen -#D perl texutil.pl --fig *.* -#D \stoptypen - -#D Of course one can also say \type{--interface=nl}, which -#D happens to be my native language. - -#D I won't go into too much detail on the algoritms used. -#D The next few pages show the functionality as reported by the -#D helpinformation and controled by command line arguments -#D and can serve as additional documentation. - -#D \TEXUTIL\ can handle different tasks; which one is active -#D depends on the command line arguments. These are handled by -#D a \PERL\ system module. This means that, at least for the -#D moment, there is no external control as provided by the -#D \PRAGMA\ environment system. - -use Getopt::Long ; -use FindBin ; - -#D We don't want error messages and accept partial switches, -#D which saves users some typing. - -$Getopt::Long::passthrough = 1 ; # no error message -$Getopt::Long::autoabbrev = 1 ; # partial switch accepted - -#D We also predefine the interface language and set a boolean -#D that keeps track of unknown options. \voetnoot {This feature -#D is still to be implemented.} - -$UserInterface = "en" ; -$UnknownOptions = 0 ; -$TcXPath = '' ; - -#D We need this for calling GS. - -use Config ; - -my $dosish = ($Config{'osname'} =~ /^(ms)?dos|^os\/2|^(ms|cyg)win/i) ; - -#D Here come the options: - -&GetOptions - ("references" => \$ProcessReferences, - "ij" => \$ProcessIJ, - "high" => \$ProcessHigh, - "quotes" => \$ProcessQuotes, - "tcxpath=s" => \$TcXPath, - "documents" => \$ProcessDocuments, - "type=s" => \$ProcessType, - "outputfile=s" => \$ProcessOutputFile, - "sources" => \$ProcessSources, - "setups" => \$ProcessSetups, - "templates" => \$ProcessTemplates, - "infos" => \$ProcessInfos, - "figures" => \$ProcessFigures, - "epspage" =>\$ProcessEpsPage, - "epstopdf" =>\$ProcessEpsToPdf, - "logfile" => \$ProcessLogFile, - "box" =>\$ProcessBox, - "hbox" =>\$ProcessHBox, - "vbox" =>\$ProcessVBox, - "criterium=f" =>\$ProcessCriterium, - "unknown" =>\$ProcessUnknown, - "purge" => \$PurgeFiles, - "purgeall" => \$PurgeAllFiles, - "analyze" => \$AnalyzeFile, - "filter" => \$FilterPages, - "help" => \$ProcessHelp, - "silent" => \$ProcessSilent, - "verbose" => \$ProcessVerbose, - "interface=s" => \$UserInterface) ; - -# A bit old, this code, could be an array. Anyhow, we will -# replace texutil soon. - -$InputFile = "@ARGV" ; # niet waterdicht - -#D We need some hacks to suppress terminal output. This -#D piece of code is based on page~193 of "Programming Perl". - -$ProgramLog = "texutil.log" ; - -# Well, it seems that unix' symlinks are sensitive for being -# hijacked. The assumption is that a known file can be a problem. -# Of course when one knows that certains files are processed, -# the names are always known and hijacking can always take -# place. But let's use a slightly less predictable name here: -# -# if ((@ARGV[0]) && (@ARGV[0] ne "")) { -# $ProgramLog = "@ARGV[0]-$ProgramLog" ; -# } else { -# # no need to be silent -# $ProcessSilent = 0 ; -# } -# -# or better, let's drop this feature, since i'm not in the mood -# now to test hacks like this (i'll just wait till the age of -# computer anarchy has ended). - -$ProgramLog = "/dev/null" ; - -# Maybe we should just write to the nul device. (In the rewritten -# version I can treat unix more strick.) - -sub RedirectTerminal - { open SAVEDSTDOUT, ">&STDOUT" ; - open STDOUT, ">$ProgramLog" ; - select STDOUT; $| = 1 } - -#D And, indeed: - -if ($ProcessSilent) - { RedirectTerminal } -else - { $ProcessVerbose = 0 } - -#D We can temporary open the terminal channel. - -sub OpenTerminal - { close STDOUT ; - open STDOUT, ">&SAVEDSTDOUT" } - -sub CloseTerminal - { open SAVEDSTDOUT, ">&STDOUT" ; - open STDOUT, ">>$ProgramLog" ; - select STDOUT; $| = 1 } - -#D By default wildcards are expanded into a list. The -#D subroutine below is therefore only needed when no file or -#D pattern is given. - -sub CompFileName - { my ($a,$b) = @_ ; - my ($fa,$sa) = split(/\./,$a) ; - my ($fb,$sb) = split(/\./,$b) ; - if (($sa =~ /^\d+$/o)&&($sb =~ /^\d+$/o)) - { $a = $fa . "." . sprintf("%10d",$sa) ; $a =~ s/\s/0/o ; - $b = $fb . "." . sprintf("%10d",$sb) ; $b =~ s/\s/0/o } - return (lc ($a) cmp lc ($b)) } - -sub CheckInputFiles - { @UserSuppliedFiles = glob $_[0] ; - @UserSuppliedFiles = sort { CompFileName($a,$b) } @UserSuppliedFiles } - -#D The next subroutine takes care of the optional output -#D filename (e.g. for figure dimensions). - -$ProcessOutputFile = "" ; - -my $Rubish ; - -sub SetOutputFile - { ($OutFilNam, $OutFilSuf) = split (/\./, $_[0], 2) ; - unless ($ProcessOutputFile eq "") - { $ProcessOutputFile .= "." . $OutFilSuf ; - ($OutFilNam, $OutFilSuf, $Rubish) = split (/\./, $ProcessOutputFile , 3)} - $OutputFile = $OutFilNam . "." . $OutFilSuf } - -#D Sometimes we need to split filenames. - -my ($FileName, $FileSuffix) = ("","") ; - -sub SplitFileName - { my $Rubish = "" ; - if ($_[0] =~ /^\.\//) - { ($Rubish, $FileName) = split ( /^\.\//, $_[0], 2) } - else - { $FileName = $_[0] } - return split (/\./, $FileName, 2) } - -#D In order to support multiple interfaces, we save the -#D messages in a hash table. As a bonus we can get a quick -#D overview of the messages we deal with. - -my %MS ; - -sub Report - { foreach $_ (@_) - { if (! defined $MS{$_}) - { print $_ } - else - { print $MS{$_} } - print " " } - print "\n" } - -#D The messages are saved in a hash table and are called -#D by name. This contents of this table depends on the -#D interface language in use. - -#D \startcompressdefinitions - -if ($UserInterface eq "nl") - - { # begin of dutch section - - $MS{"ProcessingReferences"} = "commando's, lijsten en indexen verwerken" ; - $MS{"MergingReferences"} = "indexen samenvoegen" ; - $MS{"GeneratingDocumentation"} = "ConTeXt documentatie file voorbereiden" ; - $MS{"GeneratingSources"} = "ConTeXt broncode file genereren" ; - $MS{"FilteringDefinitions"} = "ConTeXt definities filteren" ; - $MS{"CopyingTemplates"} = "TeXEdit toets templates copieren" ; - $MS{"CopyingInformation"} = "TeXEdit help informatie copieren" ; - $MS{"GeneratingFigures"} = "figuur file genereren" ; - $MS{"FilteringLogFile"} = "log file filteren (poor mans version)" ; - - $MS{"SortingIJ"} = "IJ sorteren onder Y" ; - $MS{"ConvertingHigh"} = "hoge ASCII waarden converteren" ; - $MS{"ProcessingQuotes"} = "characters met accenten afhandelen" ; - $MS{"ForcingFileType"} = "filetype instellen" ; - $MS{"UsingEps"} = "EPS files afhandelen" ; - $MS{"UsingTif"} = "TIF files afhandelen" ; - $MS{"UsingPdf"} = "PDF files afhandelen" ; - $MS{"UsingPng"} = "PNG files afhandelen" ; - $MS{"UsingJpg"} = "JPG files afhandelen" ; - $MS{"EpsToPdf"} = "EPS converteren naar PDF"; - $MS{"EpsPage"} = "EPS pagina instellen"; - $MS{"FilteringBoxes"} = "overfull boxes filteren" ; - $MS{"ApplyingCriterium"} = "criterium toepassen" ; - $MS{"FilteringUnknown"} = "onbekende ... filteren" ; - - $MS{"NoInputFile"} = "geen invoer file opgegeven" ; - $MS{"NoOutputFile"} = "geen uitvoer file gegenereerd" ; - $MS{"EmptyInputFile"} = "lege invoer file" ; - $MS{"NotYetImplemented"} = "nog niet beschikbaar" ; - - $MS{"Action"} = " actie :" ; - $MS{"Option"} = " optie :" ; - $MS{"Error"} = " fout :" ; - $MS{"Remark"} = " opmerking :" ; - $MS{"SystemCall"} = " systeemaanroep :" ; - $MS{"BadSystemCall"} = " foute systeemaanroep :" ; - $MS{"MissingSubroutine"} = " onbekende subroutine :" ; - - $MS{"EmbeddedFiles"} = " gebruikte files :" ; - $MS{"BeginEndError"} = " b/e fout in :" ; - $MS{"SynonymEntries"} = " aantal synoniemen :" ; - $MS{"SynonymErrors"} = " fouten :" ; - $MS{"RegisterEntries"} = " aantal ingangen :" ; - $MS{"RegisterErrors"} = " fouten :" ; - $MS{"PassedCommands"} = " aantal commando's :" ; - - $MS{"MultiPagePdfFile"} = " te veel pagina's :" ; - $MS{"MissingMediaBox"} = " geen mediabox :" ; - $MS{"MissingBoundingBox"} = " geen boundingbox :" ; - - $MS{"NOfDocuments"} = " documentatie blokken :" ; - $MS{"NOfDefinitions"} = " definitie blokken :" ; - $MS{"NOfSkips"} = " overgeslagen blokken :" ; - $MS{"NOfSetups"} = " gecopieerde setups :" ; - $MS{"NOfTemplates"} = " gecopieerde templates :" ; - $MS{"NOfInfos"} = " gecopieerde helpinfos :" ; - $MS{"NOfFigures"} = " verwerkte figuren :" ; - $MS{"NOfBoxes"} = " te volle boxen :" ; - $MS{"NOfUnknown"} = " onbekende ... :" ; - - $MS{"InputFile"} = " invoer file :" ; - $MS{"OutputFile"} = " outvoer file :" ; - $MS{"FileType"} = " type file :" ; - $MS{"EpsFile"} = " eps file :" ; - $MS{"PdfFile"} = " pdf file :" ; - $MS{"TifFile"} = " tif file :" ; - $MS{"PngFile"} = " png file :" ; - $MS{"JpgFile"} = " jpg file :" ; - $MS{"MPFile"} = " metapost file :" ; - - $MS{"LoadedFilter"} = " geladen filter :" ; - $MS{"RemappedKeys"} = " onderschepte keys :" ; - $MS{"WrongFilterPath"} = " fout filter pad :" ; - - $MS{"Overfull"} = "te vol" ; - $MS{"Entries"} = "ingangen" ; - $MS{"References"} = "verwijzingen" ; - - $MS{"PlugInInit"} = " plugin initialized :" ; - $MS{"PlugInReport"} = " plugin report :" ; - - } # end of dutch section - -elsif ($UserInterface eq "de") - - { # begin of german section - - $MS{"ProcessingReferences"} = "Verarbeiten der Befehle, Listen und Register" ; - $MS{"MergingReferences"} = "Register verschmelzen" ; - $MS{"GeneratingDocumentation"} = "Vorbereiten der ConTeXt-Dokumentationsdatei" ; - $MS{"GeneratingSources"} = "Erstellen einer nur Quelltext ConTeXt-Datei" ; - $MS{"FilteringDefinitions"} = "Filtern der ConTeXt-Definitionen" ; - $MS{"CopyingTemplates"} = "Kopieren der TeXEdit-Test-key-templates" ; - $MS{"CopyingInformation"} = "Kopieren der TeXEdit-Hilfsinformation" ; - $MS{"GeneratingFigures"} = "Erstellen einer Abb-Uebersichtsdatei" ; - $MS{"FilteringLogFile"} = "Filtern der log-Datei" ; - - $MS{"SortingIJ"} = "Sortiere IJ nach Y" ; - $MS{"ConvertingHigh"} = "Konvertiere hohe ASCII-Werte" ; - $MS{"ProcessingQuotes"} = "Verarbeiten der Akzentzeichen" ; - $MS{"ForcingFileType"} = "Dateityp einstellen" ; - $MS{"UsingEps"} = "EPS-Dateien verarbeite" ; - $MS{"UsingTif"} = "TIF-Dateien verarbeite" ; - $MS{"UsingPdf"} = "PDF-Dateien verarbeite" ; - $MS{"UsingPng"} = "PNG-Dateien verarbeite" ; - $MS{"UsingJpg"} = "JPG-Dateien verarbeite" ; - $MS{"EpsToPdf"} = "convert EPS to PDF"; - $MS{"EpsPage"} = "setup EPS page"; - - $MS{"FilteringBoxes"} = "Filtern der ueberfuellten Boxen" ; - $MS{"ApplyingCriterium"} = "Anwenden des uebervoll-Kriteriums" ; - $MS{"FilteringUnknown"} = "Filter unbekannt ..." ; - - $MS{"NoInputFile"} = "Keine Eingabedatei angegeben" ; - $MS{"NoOutputFile"} = "Keine Ausgabedatei generiert" ; - $MS{"EmptyInputFile"} = "Leere Eingabedatei" ; - $MS{"NotYetImplemented"} = "Noch nicht verfuegbar" ; - - $MS{"Action"} = " Aktion :" ; - $MS{"Option"} = " Option :" ; - $MS{"Error"} = " Fehler :" ; - $MS{"Remark"} = " Anmerkung :" ; - $MS{"SystemCall"} = " system call :" ; - $MS{"BadSystemCall"} = " bad system call :" ; - $MS{"MissingSubroutine"} = " missing subroutine :" ; - $MS{"SystemCall"} = " Systemaufruf :" ; - $MS{"BadSystemCall"} = " Fehlerhafter Aufruf :" ; - $MS{"MissingSubroutine"} = " Fehlende Unterroutine :" ; - - $MS{"EmbeddedFiles"} = " Eingebettete Dateien :" ; - $MS{"BeginEndError"} = " Beg./Ende-Fehler in :" ; - $MS{"SynonymEntries"} = " Synonymeintraege :" ; - $MS{"SynonymErrors"} = " Fehlerhafte Eintraege :" ; - $MS{"RegisterEntries"} = " Registereintraege :" ; - $MS{"RegisterErrors"} = " Fehlerhafte Eintraege :" ; - $MS{"PassedCommands"} = " Verarbeite Befehle :" ; - - $MS{"MultiPagePdfFile"} = " zu viele Seiten :" ; - $MS{"MissingMediaBox"} = " fehlende mediabox :" ; - $MS{"MissingBoundingBox"} = " fehlende boundingbox :" ; - - $MS{"NOfDocuments"} = " Dokumentbloecke :" ; - $MS{"NOfDefinitions"} = " Definitionsbloecke :" ; - $MS{"NOfSkips"} = "Uebersprungene Bloecke :" ; - $MS{"NOfSetups"} = " Kopierte setups :" ; - $MS{"NOfTemplates"} = " Kopierte templates :" ; - $MS{"NOfInfos"} = " Kopierte helpinfos :" ; - $MS{"NOfFigures"} = " Verarbeitete Abb. :" ; - $MS{"NOfBoxes"} = " Zu volle Boxen :" ; - $MS{"NOfUnknown"} = " Unbekannt ... :" ; - - $MS{"InputFile"} = " Eingabedatei :" ; - $MS{"OutputFile"} = " Ausgabedatei :" ; - $MS{"FileType"} = " Dateityp :" ; - $MS{"EpsFile"} = " eps-Datei :" ; - $MS{"PdfFile"} = " pdf-Datei :" ; - $MS{"TifFile"} = " tif-Datei :" ; - $MS{"PngFile"} = " png-Datei :" ; - $MS{"JpgFile"} = " jpg-Datei :" ; - $MS{"MPFile"} = " metapost-Datei :" ; - - $MS{"LoadedFilter"} = " loaded filter :" ; # tobias - $MS{"RemappedKeys"} = " remapped keys :" ; # tobias - $MS{"WrongFilterPath"} = " wrong filter path :" ; # tobias - - $MS{"Overfull"} = "zu voll" ; - $MS{"Entries"} = "Eintraege" ; - $MS{"References"} = "Referenzen" ; - - $MS{"ExtraProgram"} = " extra program :" ; - $MS{"PlugInInit"} = " plugin initialized :" ; - $MS{"PlugInReport"} = " plugin report :" ; - - } # end of german section - -elsif ($UserInterface eq "it") - - { # begin of italian section - - $MS{"ProcessingReferences"} = "elaborazione di comandi, liste e registri" ; - $MS{"MergingReferences"} = "fusione dei registri" ; - $MS{"GeneratingDocumentation"} = "preparazione del file di documentazione ConTeXt" ; - $MS{"GeneratingSources"} = "generazione del solo sorgente ConTeXt" ; - $MS{"FilteringDefinitions"} = "filtraggio delle definizioni formali ConTeXt" ; - $MS{"CopyingTemplates"} = "copia dei modelli rapidi di voci di TeXEdit" ; - $MS{"CopyingInformation"} = "copia delle informazioni di aiuto di TeXEdit" ; - $MS{"GeneratingFigures"} = "generazione del file di elengo delle figure" ; - $MS{"FilteringLogFile"} = "filtraggio del file di log" ; - - $MS{"SortingIJ"} = "IJ elencato sotto Y" ; - $MS{"ConvertingHigh"} = "conversione dei valori ASCII alti" ; - $MS{"ProcessingQuotes"} = "elaborazione dei caratteri accentati" ; - $MS{"ForcingFileType"} = "impostazine del tipo di file" ; - $MS{"UsingEps"} = "elaborazione del file EPS" ; - $MS{"UsingTif"} = "elaborazione del file TIF" ; - $MS{"UsingPdf"} = "elaborazione del file PDF" ; - $MS{"UsingPng"} = "elaborazione del file PNG" ; - $MS{"UsingJpg"} = "elaborazione del file JPG" ; - $MS{"EpsToPdf"} = "conversione da EPS a PDF"; - $MS{"EpsPage"} = "impostazione pagina EPS"; - - $MS{"FilteringBoxes"} = "filtraggio delle overfull boxes" ; - $MS{"ApplyingCriterium"} = "applicazione del criterio overfull" ; - $MS{"FilteringUnknown"} = "filtraggio dei messaggi non conosciuti ..." ; - - $MS{"NoInputFile"} = "nessun file di input specificato" ; - $MS{"NoOutputFile"} = "nessun file di output generato" ; - $MS{"EmptyInputFile"} = "file di input vuoto" ; - $MS{"NotYetImplemented"} = "non ancora disponibile" ; - - $MS{"Action"} = " azione :" ; - $MS{"Option"} = " opzione :" ; - $MS{"Error"} = " errore :" ; - $MS{"Remark"} = " commento :" ; - $MS{"SystemCall"} = " chiamata di sistema :" ; - $MS{"BadSystemCall"} = "chiamata di sistema er :" ; # GB: Hans, I need more space! - $MS{"MissingSubroutine"} = " subroutine mancante :" ; - - $MS{"EmbeddedFiles"} = " file inclusi :" ; - $MS{"BeginEndError"} = " errore di i/f in :" ; - $MS{"SynonymEntries"} = " voci di sinonimi :" ; - $MS{"SynonymErrors"} = " voci errate :" ; - $MS{"RegisterEntries"} = " voci di registro :" ; - $MS{"RegisterErrors"} = " voci errate :" ; - $MS{"PassedCommands"} = " comandi passati :" ; - - $MS{"MultiPagePdfFile"} = " troppe pagine :" ; - $MS{"MissingMediaBox"} = " mediabox mancante :" ; - $MS{"MissingBoundingBox"} = " boundingbox mancante :" ; - - $MS{"NOfDocuments"} = " blocchi di documento :" ; - $MS{"NOfDefinitions"} = "blocchi di definizioni :" ; - $MS{"NOfSkips"} = " blocchi saltati :" ; - $MS{"NOfSetups"} = " impostazioni copiate :" ; - $MS{"NOfTemplates"} = " modelli copiati :" ; - $MS{"NOfInfos"} = " helpinfo copiati :" ; - $MS{"NOfFigures"} = " figure elaborate :" ; - $MS{"NOfBoxes"} = " overfull boxes :" ; - $MS{"NOfUnknown"} = " sconosciuti ... :" ; - - $MS{"InputFile"} = " file di input :" ; - $MS{"OutputFile"} = " file di output :" ; - $MS{"FileType"} = " tipo di file :" ; - $MS{"EpsFile"} = " file eps :" ; - $MS{"PdfFile"} = " file pdf :" ; - $MS{"TifFile"} = " file tif :" ; - $MS{"PngFile"} = " file png :" ; - $MS{"JpgFile"} = " file jpg :" ; - $MS{"MPFile"} = " file metapost :" ; - - $MS{"LoadedFilter"} = " filtro caricato :" ; - $MS{"RemappedKeys"} = " voci rimappate :" ; - $MS{"WrongFilterPath"} = "percorso filtro errato :" ; - - $MS{"Overfull"} = "overfull" ; - $MS{"Entries"} = "voci" ; - $MS{"References"} = "riferimenti" ; - - $MS{"ExtraProgram"} = " extra program :" ; - $MS{"PlugInInit"} = " plugin initialized :" ; - $MS{"PlugInReport"} = " plugin report :" ; - - } # end of italian section - -else - - { # begin of english section - - $MS{"ProcessingReferences"} = "processing commands, lists and registers" ; - $MS{"MergingReferences"} = "merging registers" ; - $MS{"GeneratingDocumentation"} = "preparing ConTeXt documentation file" ; - $MS{"GeneratingSources"} = "generating ConTeXt source only file" ; - $MS{"FilteringDefinitions"} = "filtering formal ConTeXt definitions" ; - $MS{"CopyingTemplates"} = "copying TeXEdit quick key templates" ; - $MS{"CopyingInformation"} = "copying TeXEdit help information" ; - $MS{"GeneratingFigures"} = "generating figure directory file" ; - $MS{"FilteringLogFile"} = "filtering log file" ; - - $MS{"SortingIJ"} = "sorting IJ under Y" ; - $MS{"ConvertingHigh"} = "converting high ASCII values" ; - $MS{"ProcessingQuotes"} = "handling accented characters" ; - $MS{"ForcingFileType"} = "setting up filetype" ; - $MS{"UsingEps"} = "processing EPS-file" ; - $MS{"UsingTif"} = "processing TIF-file" ; - $MS{"UsingPdf"} = "processing PDF-file" ; - $MS{"UsingPng"} = "processing PNG-file" ; - $MS{"UsingJpg"} = "processing JPG-file" ; - $MS{"EpsToPdf"} = "convert EPS to PDF"; - $MS{"EpsPage"} = "setup EPS page"; - - $MS{"FilteringBoxes"} = "filtering overfull boxes" ; - $MS{"ApplyingCriterium"} = "applying overfull criterium" ; - $MS{"FilteringUnknown"} = "filtering unknown ..." ; - - $MS{"NoInputFile"} = "no input file given" ; - $MS{"NoOutputFile"} = "no output file generated" ; - $MS{"EmptyInputFile"} = "empty input file" ; - $MS{"NotYetImplemented"} = "not yet available" ; - - $MS{"Action"} = " action :" ; - $MS{"Option"} = " option :" ; - $MS{"Error"} = " error :" ; - $MS{"Remark"} = " remark :" ; - $MS{"SystemCall"} = " system call :" ; - $MS{"BadSystemCall"} = " bad system call :" ; - $MS{"MissingSubroutine"} = " missing subroutine :" ; - - $MS{"EmbeddedFiles"} = " embedded files :" ; - $MS{"BeginEndError"} = " b/e error in :" ; - $MS{"SynonymEntries"} = " synonym entries :" ; - $MS{"SynonymErrors"} = " bad entries :" ; - $MS{"RegisterEntries"} = " register entries :" ; - $MS{"RegisterErrors"} = " bad entries :" ; - $MS{"PassedCommands"} = " passed commands :" ; - - $MS{"MultiPagePdfFile"} = " too many pages :" ; - $MS{"MissingMediaBox"} = " missing mediabox :" ; - $MS{"MissingBoundingBox"} = " missing boundingbox :" ; - - $MS{"NOfDocuments"} = " document blocks :" ; - $MS{"NOfDefinitions"} = " definition blocks :" ; - $MS{"NOfSkips"} = " skipped blocks :" ; - $MS{"NOfSetups"} = " copied setups :" ; - $MS{"NOfTemplates"} = " copied templates :" ; - $MS{"NOfInfos"} = " copied helpinfos :" ; - $MS{"NOfFigures"} = " processed figures :" ; - $MS{"NOfBoxes"} = " overfull boxes :" ; - $MS{"NOfUnknown"} = " unknown ... :" ; - - $MS{"InputFile"} = " input file :" ; - $MS{"OutputFile"} = " output file :" ; - $MS{"FileType"} = " file type :" ; - $MS{"EpsFile"} = " eps file :" ; - $MS{"PdfFile"} = " pdf file :" ; - $MS{"TifFile"} = " tif file :" ; - $MS{"PngFile"} = " png file :" ; - $MS{"JpgFile"} = " jpg file :" ; - $MS{"MPFile"} = " metapost file :" ; - - $MS{"LoadedFilter"} = " loaded filter :" ; - $MS{"RemappedKeys"} = " remapped keys :" ; - $MS{"WrongFilterPath"} = " wrong filter path :" ; - - $MS{"Overfull"} = "overfull" ; - $MS{"Entries"} = "entries" ; - $MS{"References"} = "references" ; - - $MS{"ExtraProgram"} = " extra program :" ; - $MS{"PlugInInit"} = " plugin initialized :" ; - $MS{"PlugInReport"} = " plugin report :" ; - - } # end of english section - -#D \stopcompressdefinitions - -#D Showing the banner (name and version of the program) and -#D offering helpinfo is rather straightforward. - -sub ShowBanner - { Report("\n $Program\n") } - -sub ShowHelpInfo - { Report("HelpInfo") } - -#D The helpinfo is also saved in the hash table. This looks -#D like a waste of energy and space, but the program gains -#D readability. - -#D \startcompressdefinitions - -if ($UserInterface eq "nl") - - { # begin of dutch section - - $MS{"HelpInfo"} = - -" --references hulp file verwerken / tui->tuo \n" . -" --ij : IJ als Y sorteren \n" . -" --high : hoge ASCII waarden converteren \n" . -" --quotes : quotes converteren \n" . -" --tcxpath : tcx filter pad \n" . -" \n" . -" --purge(all) tijdelijke (klad) files verwijderen \n" . -" \n" . -" --documents documentatie file genereren / tex->ted \n" . -" --sources broncode file genereren / tex->tes \n" . -" --setups ConTeXt definities filteren / tex->texutil.tus \n" . -" --templates TeXEdit templates filteren / tex->tud \n" . -" --infos TeXEdit helpinfo filteren / tex->tud \n" . -" \n" . -" --figures eps figuren lijst genereren / *->texutil.tuf \n" . -" --epspage : voorbereiden voor pdf \n" . -" --epstopdf : omzetten naar pdf \n" . -" \n" . -" --logfile logfile filteren / log->$ProgramLog \n" . -" --box : overfull boxes controleren \n" . -" --criterium : overfull criterium in pt \n" . -" --unknown :onbekende ... controleren \n" ; - - } # end of dutch section - -elsif ($UserInterface eq "de") - - { # begin of german section - - $MS{"HelpInfo"} = - -" --references Verarbeiten der Hilfsdatei / tui->tuo \n" . -" --ij : Sortiere IJ als Y \n" . -" --high : Konvertiere hohe ASCII-Werte \n" . -" --quotes : Konvertiere akzentuierte Buchstaben \n" . -" --tcxpath : tcx Filter Path \n" . -" \n" . -" --purge(all) entferne temporaere ConTeXt-Dateien \n" . -" \n" . -" --documents Erstelle Dokumentationsdatei / tex->ted \n" . -" --sources Erstelle reine Quelltextdateien / tex->tes \n" . -" --setups Filtere ConTeXt-Definitionen / tex->texutil.tus\n" . -" --templates Filtere TeXEdit-templates / tex->tud \n" . -" --infos Filtere TeXEdit-helpinfo / tex->tud \n" . -" \n" . -" --figures Erstelle eps-Abbildungsliste / *->texutil.tuf \n" . -" --epspage : Bereite fuer pdf vor \n" . -" --epstopdf : Konvertiere zu pdf \n" . -" \n" . -" --logfile Filtere log-Datei / log->$ProgramLog \n" . -" --box : Ueberpruefe uebervolle Boxen \n" . -" --criterium : Uebervoll-Kriterium in pt \n" . -" --unknown : Ueberpruefe auf unbekannte ... \n" ; - - } # end of german section - -elsif ($UserInterface eq "it") - - { # begin of italian section GB: Hans, I need more space! - - $MS{"HelpInfo"} = - -" --references elabora file ausiliari / tui->tuo \n" . -" --ij : elenca IJ come Y \n" . -" --high : converti i valori ASCII alti \n" . -" --quotes : converti caratteri accentati \n" . -" --tcxpath : percorso del filtro tcx \n" . -" \n" . -" --purge(all) rimuovi i file temporanei ConTeXt \n" . -" \n" . -" --documents genera file di documentazione / tex->ted \n" . -" --sources genera solo sorgente / tex->tes \n" . -" --setups filtra definizioni ConTeXt / tex->texutil.tus \n" . -" --templates filtra modelli TeXEdit / tex->tud \n" . -" --infos filtra helpinfo TeXEdit / tex->tud \n" . -" \n" . -" --figures genera lista figure eps / *->texutil.tuf \n" . -" --epspage : prepara per pdf \n" . -" --epstopdf : converti in pdf \n" . -" \n" . -" --logfile filtra logfile / log->$ProgramLog \n" . -" --box : controlla overful boxes \n" . -" --criterium : criterio overfull in pt \n" . -" --unknown : controlla sconosciuti ... \n" ; - - } # end of italian section - -else - - { # begin of english section - - $MS{"HelpInfo"} = - -" --references process auxiliary file / tui->tuo \n" . -" --ij : sort IJ as Y \n" . -" --high : convert high ASCII values \n" . -" --quotes : convert quotes characters \n" . -" --tcxpath : tcx filter path \n" . -" \n" . -" --purge(all) clean up temporary context files \n" . -" \n" . -" --documents generate documentation file / tex->ted \n" . -" --sources generate source only file / tex->tes \n" . -" --setups filter ConTeXt definitions / tex->texutil.tus \n" . -" --templates filter TeXEdit templates / tex->tud \n" . -" --infos filter TeXEdit helpinfo / tex->tud \n" . -" \n" . -" --figures generate eps figure list / *->texutil.tuf \n" . -" --epspage : prepare for pdf \n" . -" --epstopdf : convert to pdf \n" . -" \n" . -" --logfile filter logfile / log->$ProgramLog \n" . -" --box : check overful boxes \n" . -" --criterium : overfull criterium in pt \n" . -" --unknown : check unknown ... \n" ; - - } # end of english section - -#D \stopcompressdefinitions - -#D In order to sort strings correctly, we have to sanitize -#D them. This is especially needed when we include \TEX\ -#D commands, quotes characters and compound word placeholders. -#D -#D \startopsomming[opelkaar] -#D \som \type{\name}: csnames are stripped -#D \som \type{{}}: are removed -#D \som \type{\"e}: and alike are translated into \type{"e} etc. -#D \som \type{"e}: is translated into an \type{e} and \type{b} etc. -#D \som \type{||}: becomes \type{-} -#D \som \type{\-}: also becomes \type{-} -#D \som \type{<*..>}: becomes \type{..} (internal XML entity) -#D \stopopsomming -#D -#D Of course other accented characters are handled too. The -#D appended string is responsible for decent sorting. -#D -#D \startPL -#D $TargetString = SanitizedString ( $SourceString ) ; -#D \stopPL -#D -#D The sort order depends on the ordering in array -#D \type{$ASCII}: - -$ASCII{"^"} = "a" ; $ASCII{'"'} = "b" ; $ASCII{"`"} = "c" ; -$ASCII{"'"} = "d" ; $ASCII{"~"} = "e" ; $ASCII{","} = "f" ; - -#sub SanitizedString -# { my ($string) = $_[0] ; -# if ($ProcessQuotes) -# { $string =~ s/\\([\^\"\`\'\~\,])/$1/gio ; -# $copied = $string ; -# $copied =~ s/([\^\"\`\'\~\,])([a-zA-Z])/$ASCII{$1}/gio ; -# $string =~ s/([\^\"\`\'\~\,])([a-zA-Z])/$2/gio ; -# $string=$string.$copied } -# $string =~ s/\\-|\|\|/\-/gio ; -# $string =~ s/\\[a-zA-Z]*| |\{|\}//gio ; -# return $string } - -#D YET UNDOCUMENTED - -my $SortN = 0 ; my @Filter ; - -# copied from texexec - -my @paths ; -my $kpsewhich = '' ; -my $pathslash = '/' ; if ($0 =~ /\\/) { $pathslash = "\\" } - -sub checked_path - { my $path = shift ; - if ((defined($path))&&($path ne '')) - { $path =~ s/[\/\\]/$pathslash/go ; - $path =~ s/[\/\\]*$//go ; - $path .= $pathslash } - else - { $path = '' } - return $path } - -if ($ENV{PATH} =~ /\;/) - { @paths = split(/\;/,$ENV{PATH}) } -else - { @paths = split(/\:/,$ENV{PATH}) } - -# until here. - -sub InitializeKeys - { my $filename = $ARGV[0] ; - return unless (open(TEX,"$filename.tex")) ; - for ($i=0;$i<=255;$i++) - { $Filter[$i] = $i } - if ($TcXPath eq '') - { foreach (@paths) - { my $p = checked_path($_) . 'kpsewhich' ; - if ((-e $p)||(-e $p . '.exe')) - { $kpsewhich = $p ; last } } } - $kpsewhich = "\"$kpsewhich\"" if ($kpsewhich =~ m/^[^\"].* /) ; - while (<TEX>) - { chomp ; - my $Filter ; - if (/^\%/) - { if (s/.*translat.*?=([\:\/0-9\-a-z]*)/$1/oi) - { my $Translation = $_ ; - if ($TcXPath ne '') - { $TcXPath = checked_path($TcXPath) ; - $Filter = "$TcXPath$pathslash$Translation.tcx" } - elsif ($kpsewhich ne '') - { $Filter = `$kpsewhich --format="web2c files" $Translation.tcx` ; - chomp $Filter } - else - { last } - if (open(ASC,$Filter)) - { Report ("LoadedFilter", $Translation) ; - while (<ASC>) - { if (/^(\d+)\s*(\d+)/) - { $Filter[$2] = $1 } } - close (ASC) } - elsif ($TcXPath ne '') - { Report ("WrongFilterPath", $TcXPath) } - last } } - else - { last } } - close (TEX) } - -sub HandleKey - { ++$SortN ; - $RestOfLine =~ s/\{(.*)\}/$1/o ; - my ($lan, $enc, $str, $chr, $map, $alf) = split(/\}\s*\{/, $RestOfLine) ; - if ($str =~ /^(\d+)/) { $str = ''.chr($Filter[$1]) } - $map = chr(ord($MAP[$i])+128) ; - $STR[$SortN] = $str ; - $CHR[$SortN] = $chr ; - $MAP[$SortN] = $map ; -#print "$chr$map = $alf\n" ; -# $ALF{"$chr$map"} = $alf } - $ALF{"$map"} = $alf } - -sub FlushKeys - { Report ("RemappedKeys", $SortN) } - -sub SanitizedString - { my $string = my $original = shift ; - if ($SortN) - { my $copied = $string ; - for ($i=1;$i<=$SortN;$i++) - { my $s = $STR[$i] ; - my $c = $CHR[$i] ; - my $m = $MAP[$i] ; - # print "[$i $s $c $m]\n" ; - $string =~ s/($s)/$c/ge ; - $copied =~ s/($s)/$m/ge } - $string .= "\x00"; - $string .= $copied } - elsif ($ProcessQuotes) - { $string =~ s/\\([\^\"\`\'\~\,])/$1/gio ; - $copied = $string ; - $copied =~ s/([\^\"\`\'\~\,])([a-zA-Z])/$ASCII{$1}/gi ; - $string =~ s/([\^\"\`\'\~\,])([a-zA-Z])/$2/gio ; - $string .= "\x00"; - $string .= $copied } -# new and very experimental, will change -$string =~ s/\<\*(.*?)\>/\\$1 /go ; # reduce entities / will be table too -$string =~ s/\\getXMLentity\s*\{(.*?)\}/$1/gio ; # {tex} => tex -$string =~ s/\<[a-zA-Z\/].*?\>//go ; # remove elements -# so far - $string =~ s/\\-|\|\|/\-/gio ; - $string =~ s/\\[a-zA-Z]*| |\{|\}//gio ; # ? -#print "$original $string $copied\n" ; - return $string } - -#D This subroutine looks a bit complicated, which is due to the -#D fact that we want to sort for instance an accented \type{e} -#D after the plain \type{e}, so the imaginary words -#D -#D \starttypen -#D eerste -#D \"eerste -#D \"e\"erste -#D eerst\"e -#D \stoptypen -#D -#D come out in an acceptable order. - -#D We also have to deal with the typical \TEX\ sequences with -#D the double \type{^}'s, like \type{^^45}. These hexadecimal -#D coded characters are just converted. -#D -#D \startPL -#D $TargetString = HighConverted ( $SourceString ) ; -#D \stopPL - -sub HighConverted - { my ($string) = $_[0] ; - $string =~ s/\^\^([a-f0-9][a-f0-9])/chr hex($1)/geo ; - return $string } - -#D \extras -#D {references} -#D -#D \CONTEXT\ can handle many lists, registers (indexes), -#D tables of whatever and references. This data is collected -#D in one pass and processed in a second one. In between, -#D relevant data is saved in the file \type{\jobname.tui}. -#D This file also holds some additional information concerning -#D second pass optimizations. -#D -#D The main task of \TEXUTIL\ is to sort lists and registers -#D (indexes). The results are stored in again one file called -#D \type{\jobname.tuo}. -#D -#D Just for debugging purposes the nesting of files loaded -#D during the \CONTEXT\ run is stored. Of course this only -#D applies to files that are handled by the \CONTEXT\ file -#D structuring commands (projects, products, components and -#D environments). -#D -#D We have to handle the entries: -#D -#D \starttypen -#D f b {test} -#D f e {test} -#D \stoptypen -#D -#D and only report some status info at the end of the run. - -sub InitializeFiles - { $NOfFiles = 0 ; - $NOfBadFiles = 0 } - -sub HandleFile - { $RestOfLine =~ s/.*\{(.*)\}/$1/gio ; - ++$Files{$RestOfLine} } - -sub FlushFiles # hash needs to be sorted, else problem on macosx - { print TUO "%\n" . "% $Program / Files\n" . "%\n" ; - foreach $File (sort keys %Files) - { print TUO "% $File ($Files{$File})\n" } - print TUO "%\n" ; - $NOfFiles = keys %Files ; - Report("EmbeddedFiles", $NOfFiles) ; - foreach $File (sort keys %Files) - { unless (($Files{$File} % 2) eq 0) - { ++$NOfBadFiles ; - Report("BeginEndError", $File) } } } - -#D Commands don't need a special treatment. They are just -#D copied. Such commands are tagged by a \type{c}, like: -#D -#D \starttypen -#D c \thisisutilityversion{year.month.day} -#D c \twopassentry{class}{key}{value} -#D c \mainreference{prefix}{entry}{pagenumber}{realpage}{tag} -#D c \listentry{category}{tag}{number}{title}{pagenumber}{realpage} -#D c \initializevariable\realnumberofpages{number} -#D \stoptypen -#D -#D For historic reasons we check for the presense of the -#D backslash. - -my $NOfPositionsFound = 0 ; -my $TotalNOfPositions = 0 ; -my $TotalNOfMPgraphics = 0 ; - -my $SectionSeparator = ":" ; - -sub InitializeCommands - { print TUO "%\n" . "% $Program / Commands\n" . "%\n" ; - $NOfCommands = 0 } - -sub HandleCommand - { ++$NOfCommands ; - $RestOfLine =~ s/^\\//go ; - if ($RestOfLine =~ /^pospxy/o) - { ++$NOfPositionsFound } - elsif ($RestOfLine =~ /^initializevariable\\totalnofpositions\{(.*)\}/o) - { $TotalNOfPositions = $1 } - elsif ($RestOfLine =~ /^initializevariable\\totalnofMPgraphics\{(.*)\}/o) - { $TotalNOfMPgraphics = $1 } -# todo: reg how to -# elsif ($RestOfLine =~ /^thisissectionseparator\{(.*)\}/o) -# { $SectionSeparator = $1 } - elsif ($RestOfLine =~ /^thisisbytesequence\{(.*)\}/o) - { $RestOfLine =~ s/\^//go } - print TUO "\\$RestOfLine\n" } - -sub FlushCommands - { Report ("PassedCommands", $NOfCommands) } - -#D Experimental: Extra -#D -#D s p : extra programs - -my @ExtraPrograms = () ; - -sub InitializeExtra - { } - -sub HandleExtra - { if ($RestOfLine =~ /(.)\s+(.*)\s*$/o) - { if ($1 eq "p") - { my $str = $2 ; $str =~ s/^\{(.*)\}$/$1/o ; - push @ExtraPrograms,$str } } } - -sub FlushExtra - { print TUO "%\n" . "% $Program / System\n" . "%\n" ; - foreach $EP (@ExtraPrograms) - { print TUO "% extra program : $EP\n" } } - -sub RunExtraPrograms - { foreach $EP (@ExtraPrograms) - { Report ("ExtraProgram", $EP) ; - system($EP) } } - -#D Plugins -#D -#D test.pm: -#D -#D \starttypen -#D see plugtest.pm -#D \stoptypen -#D -#D utility format: -#D -#D \starttypen -#D p u {name} {data} {data} ... -#D \stoptypen - -my $pm_path ; - -BEGIN - { ## $pm_path = `kpsewhich --format="other text files" --progname=context texutil.pl` ; - ## chomp($pm_path) ; - # $pm_path =~ s/texutil\.pl.*// } - # $pm_path = $0 ; - # $pm_path =~ s/\\/\//o ; - # $pm_path =~ s/texutil\.pl.*//io ; - ## $pm_path =~ s/(.*)texutil.*?$/$1/i ; - $pm_path = "$FindBin::Bin/" ; - if ($pm_path eq "") { $pm_path = "./" } } - -use lib $pm_path ; - -my %UserPlugIns ; - -sub HandlePlugIn - { if ($RestOfLine =~ /\s*u\s*\{(.*?)\}\s*(.*)\s*/io) - { my $tag = $1 ; - my $arg = $2 ; - if (! defined($UserPlugIns{$tag})) - { $UserPlugIns{$tag} = 1 ; - eval("use $tag") ; - my $result = $tag->identify ; - if ($result ne "") - { Report ("PlugInInit", "$tag -> $result") } - else - { Report ("PlugInInit", $tag ) } - $tag->initialize() } - if (defined($UserPlugIns{$tag})) - { $arg =~ s/\{(.*)\}/$1/o ; - my @args = split(/\}\s*\{/o, $arg) ; - $tag->handle(@args) } } } - -sub FlushPlugIns - { foreach my $tag (keys %UserPlugIns) - { my @report = $tag->report ; - foreach $rep (@report) - { my ($key,$val) = split (/\s*\:\s*/,$rep) ; - if ($val ne "") - { Report ("PlugInReport", "$tag -> $key -> $val") } - else - { Report ("PlugInReport", "$tag -> $key") } } - $tag->process ; - print TUO "%\n" . "% $Program / " . $tag->identify . "\n" . "%\n" ; - foreach my $str ($tag->results) - { print TUO "\\plugincommand\{$str\}\n" } } } - -#D Synonyms are a sort of key||value pairs and are used for -#D ordered lists like abbreviations and units. -#D -#D \starttypen -#D s e {class}{sanitized key}{key}{associated data} -#D \stoptypen -#D -#D The sorted lists are saved as (surprise): -#D -#D \starttypen -#D \synonymentry{class}{sanitized key}{key}{associated data} -#D \stoptypen - -sub InitializeSynonyms - { $NOfSynonyms = 0 ; - $NOfBadSynonyms = 0 } - -#M \definieersynoniem [testname] [testnames] [\testmeaning] -#M -#M \stelsynoniemenin [testname] [criterium=alles] - -#D Let's first make clear what we can expect. Synonym -#D entries look like: -#D -#D \startbuffer -#D \testname [alpha] {\sl alpha} {a greek letter a} -#D \testname {alpha} {another a} -#D \testname [Beta] {\kap{beta}} {a greek letter b} -#D \testname {beta} {indeed another b} -#D \testname {gamma} {something alike g} -#D \testname {delta} {just a greek d} -#D \stopbuffer -#D -#D \typebuffer -#D -#D This not that spectacular list is to be sorted according -#D to the keys (names). \haalbuffer - -sub HandleSynonym - { ++$NOfSynonyms ; - ($SecondTag, $RestOfLine) = split(/ /, $RestOfLine, 2) ; - ($Class, $Key, $Entry, $Meaning) = split(/} \{/, $RestOfLine) ; - chop $Meaning ; - $Class = substr $Class, 1 ; - if ($Entry eq "") - { ++$NOfBadSynonyms } - else - { $SynonymEntry[$NOfSynonyms] = - join ($JOIN,$Class,$Key,$Entry,$Meaning) } } - -#D Depending on the settings\voetnoot{One can call for -#D all defined entries, call only the used ones, change -#D layout, attach (funny) commands etc.} a list of -#D {\em testnames} looks like: -#D -#D \plaatslijstmettestnames -#D -#D Watch the order in which these entries are sorted. - -sub FlushSynonyms - { print TUO "%\n" . "% $Program / Synonyms\n" . "%\n" ; - @SynonymEntry = sort { lc($a) cmp lc($b) } @SynonymEntry ; - $NOfSaneSynonyms = 0 ; - for ($n=1; $n<=$NOfSynonyms; $n++) - { # check normally not needed - if (($n==1)||($SynonymEntry[$n] ne $SynonymEntry[$n-1])) - { ($Class, $Key, $Entry, $Meaning) = - split(/$JOIN/, $SynonymEntry[$n]) ; - ++$NOfSaneSynonyms ; - print TUO "\\synonymentry{$Class}{$Key}{$Entry}{$Meaning}\n" } } - Report("SynonymEntries", $NOfSynonyms, "->", $NOfSaneSynonyms, "Entries") ; - if ($NOfBadSynonyms>0) - { Report("SynonymErrors", $NOfBadSynonyms) } } - -#D Register entries need a bit more care, especially when they -#D are nested. In the near future we will also handle page -#D ranges. -#D -#D \starttypen -#D r e {class}{tag}{sanitized key}{key}{pagenumber}{realpage} -#D r s {class}{tag}{sanitized key}{key}{string}{pagenumber} -#D r r {class}{tag}{sanitized key}{key}{string}{pagenumber} -#D \stoptypen -#D -#D The last one indicates the start of a range. - -#D The first one is the normal entry, the second one concerns -#D {\em see this or that} entries. Keys are sanitized, unless -#D the user supplies a sanitized key. To save a lot of -#D programming, all data concerning an entry is stored in one -#D string. Subentries are specified as: -#D -#D \starttypen -#D first&second&third -#D first+second+third -#D \stoptypen -#D -#D When these characters are needed for typesetting purposes, we -#D can also use the first character to specify the separator: -#D -#D \starttypen -#D &$x^2+y^2=r^2$ -#D +this \& that -#D \stoptypen -#D -#D Subentries are first unpacked and next stored in a -#D consistent way, which means that we can use both separators -#D alongside each other. We leave it to the reader to sort -#D out the dirty tricks. - -$SPLIT ="%%" ; -$JOIN ="__" ; - -sub InitializeRegisters - { $NOfEntries = 0 ; - $NOfBadEntries = 0 } - -$ProcessType = "" ; - -$RegStat{"f"} = 1 ; -$RegStat{"e"} = 2 ; # end up between from and to -$RegStat{"t"} = 3 ; -$RegStat{"s"} = 4 ; - -my $RegSep = "$SectionSeparator$SectionSeparator" ; - -sub HandleRegister # the } { makes sure that local {} is ok - { ($SecondTag, $RestOfLine) = split(/ /, $RestOfLine, 2) ; - ++$NOfEntries ; - #~ if ($SecondTag eq "s") - #~ { ($Class, $Location, $Key, $Entry, $SeeToo, $Page ) = - #~ split(/} \{/, $RestOfLine) ; - #~ chop $Page ; - #~ $Class = substr $Class, 1 ; - #~ $RealPage = 0 } - #~ else - #~ { ($Class, $Location, $Key, $Entry, $Page, $RealPage ) = - #~ split(/} \{/, $RestOfLine) ; - #~ chop $RealPage ; - #~ $Class = substr $Class, 1 ; - #~ $SeeToo = "" } - if ($SecondTag eq "s") - { if ($RestOfLine =~ /^\s*(.*?)\}\s\{(.*?)\}\s\{(.*?)\}\s\{(.*)\}\s\{(.*?)\}\s\{(.*?)\s*$/o) - { ($Class, $Location, $Key, $Entry, $SeeToo, $Page ) = ($1,$2,$3,$4,$5,$6) ; - chop $Page ; - $Class = substr $Class, 1 ; - $RealPage = 0 } - else - { return } } - else - { if ($RestOfLine =~ /^\s*(.*?)\}\s\{(.*?)\}\s\{(.*?)\}\s\{(.*)\}\s\{(.*?)\}\s\{(.*?)\s*$/o) - { ($Class, $Location, $Key, $Entry, $Page, $RealPage ) = ($1,$2,$3,$4,$5,$6) ; - chop $RealPage ; - $Class = substr $Class, 1 ; - $SeeToo = "" } - else - { return } } - $_ = $Key ; - if (/$RegSep/) - { ($PageHow,$Key) = split (/$RegSep/) } - else - { $PageHow = "" } - $_ = $Entry ; - if (/$RegSep/) - { ($TextHow,$Entry) = split (/$RegSep/) } - else - { $TextHow = "" } - # - if ($Key eq "") - { $Key = SanitizedString($Entry) } - # if ($SortMethod ne '') - # { $ProcessHigh = 0 } - if ($ProcessHigh) - { $Key = HighConverted($Key) } - $KeyTag = substr $Key, 0, 1 ; - if ($KeyTag eq "&") - { $Key =~ s/^\&//go ; - $Key =~ s/([^\\])\&/$1$SPLIT/go } - elsif ($KeyTag eq "+") - { $Key =~ s/^\+//go ; - $Key =~ s/([^\\])\+/$1$SPLIT/go } - else - { $Key =~ s/([^\\])\&/$1$SPLIT/go ; - $Key =~ s/([^\\])\+/$1$SPLIT/go } - $Key .= " " ; # so, "Word" comes for "Word Another Word" - $EntryTag = substr $Entry, 0, 1 ; - if ($EntryTag eq "&") - { $Entry =~ s/^\&//go ; - $Entry =~ s/([^\\])\&/$1$SPLIT/go } - elsif ($EntryTag eq "+") - { $Entry =~ s/^\+//go ; - $Entry =~ s/([^\\])\+/$1$SPLIT/go } - elsif ($KeyTag eq "&") - { $Entry =~ s/([^\\])\&/$1$SPLIT/go } - elsif ($KeyTag eq "+") - { $Entry =~ s/([^\\])\+/$1$SPLIT/go } - else - { $Entry =~ s/([^\\])\&/$1$SPLIT/go ; - $Entry =~ s/([^\\])\+/$1$SPLIT/go } - $Key =~ s/^([^a-zA-Z])/ $1/go ; - $Key =~ s/^\s*\{(.*)\}$SPLIT/$1$SPLIT/go ; ####### new - $Entry =~ s/^\{(.*)\}$SPLIT/$1$SPLIT/go ; ###### new - if ($ProcessIJ) { $Key =~ s/ij/yy/go } - $LCKey = lc $Key ; - $RegStatus = $RegStat{$SecondTag} ; - $RealPageNumber= sprintf("%6i",$RealPage) ; - $RegisterEntry[$NOfEntries] = - join($JOIN,$Class,$LCKey,$Key,$Entry,$TextHow,$RegStatus, - $RealPageNumber,$Location,$Page,$PageHow,$SeeToo) } - -#M \definieerregister [testentry] [testentries] - -#D The previous routine deals with entries like: -#D -#D \startbuffer -#D \testentry {alpha} -#D \testentry {beta} -#D \testentry {gamma} -#D \testentry {gamma} -#D \testentry {delta} -#D \testentry {epsilon} -#D \testentry {alpha+first} -#D \testentry {alpha+second} -#D \testentry {alpha+second} -#D \testentry {alpha+third} -#D \testentry {alpha+second+one} -#D \testentry {alpha+second+one} -#D \testentry {alpha+second+two} -#D \testentry {alpha+second+three} -#D \testentry {gamma+first+one} -#D \testentry {gamma+second} -#D \testentry {gamma+second+one} -#D -#D \testentry {alpha+fourth} -#D \testentry {&alpha&fourth} -#D \testentry {+alpha+fourth} -#D -#D \testentry [alpha+fourth] {alpha+fourth} -#D \testentry [&alpha&fourth&one] {&alpha&fourth&one} -#D \testentry [+alpha+fourth+two] {&alpha&fourth&two} -#D -#D \testentry {\kap{alpha}+fifth} -#D \testentry {\kap{alpha}+f\'ifth} -#D \testentry {\kap{alpha}+f"ifth} -#D -#D \testentry [&betaformula] {&$a^2+b^2=c^2$} -#D -#D \testentry {zeta \& more} -#D -#D \testentry [pagehowto::key]{texthowto::entry} -#D -#D % a very special case, when key has , and is constructed -#D -#D \testentry [pagehowto::{key}]{texthowto::{entry}} -#D -#D \stopbuffer -#D -#D \typebuffer -#D -#D \haalbuffer After being sorted, these entries are -#D turned into something \TEX\ using: - -$CollapseEntries = 0 ; - -$RegisterEntry[0] = ("") ; - -sub How - { return "$TextHow$RegSep" . "$_[0]" } - -sub FlushSavedLine - { if (($CollapseEntries)&&($SavedFrom ne "")) - { if ($SavedTo ne "") - { print TUO "\\registerfrom$SavedFrom" ; - print TUO "\\registerto$SavedTo" } - else - { print TUO "\\registerpage$SavedFrom" } } - $SavedHow = "" ; - $SavedFrom = "" ; - $SavedTo = "" ; - $SavedEntry = "" } - -sub FlushRegisters - { print TUO "%\n" . "% $Program / Registers\n" . "%\n" ; - @RegisterEntry = sort { lc($a) cmp lc($b) } @RegisterEntry ; - $NOfSaneEntries = 0 ; - $NOfSanePages = 0 ; - $LastPage = "" ; - $LastRealPage = "" ; - $AlfaClass = "" ; - $Alfa = "" ; - $PreviousA = "" ; - $PreviousB = "" ; - $PreviousC = "" ; - $ActualA = "" ; - $ActualB = "" ; - $ActualC = "" ; - - $SavedFrom = "" ; - $SavedTo = "" ; - $SavedEntry = "" ; - $SavedHow = "" ; - - for ($n=1 ; $n<=$NOfEntries ; ++$n) - { ($Class, $LCKey, $Key, $Entry, $TextHow, $RegisterState, - $RealPage, $Location, $Page, $PageHow, $SeeToo) = - split(/$JOIN/, $RegisterEntry[$n]) ; - $RealPage =~ s/^\s*//o ; - $TestAlfa = lc substr $Key, 0, 1 ; - # - if ($SortN) - { $AlfKey = $Key ; - $AlfKey =~ s/(.).*\x00(.).*/$2/o ; - if (defined($ALF{$AlfKey})) - { $TestAlfa = $ALF{$AlfKey} } } - # - if ((lc $TestAlfa ne lc $Alfa) or ($AlfaClass ne $Class)) - { # $Alfa= lc substr $Key, 0, 1 ; - $Alfa = $TestAlfa ; - $AlfaClass = $Class ; - if ($Alfa ne " ") - { FlushSavedLine ; - print TUO "\\registerentry{$Class}{$Alfa}\n" } } - ($ActualA, $ActualB, $ActualC ) = - split(/$SPLIT/, $Entry, 3) ; - unless ($ActualA) { $ActualA = "" } - unless ($ActualB) { $ActualB = "" } - unless ($ActualC) { $ActualC = "" } - if (How($ActualA) eq $PreviousA) - { $ActualA = "" } - else - { $PreviousA = How($ActualA) ; - $PreviousB = "" ; - $PreviousC = "" } - if (How($ActualB) eq $PreviousB) - { $ActualB = "" } - else - { $PreviousB = How($ActualB) ; - $PreviousC = "" } - if (How($ActualC) eq $PreviousC) - { $ActualC = "" } - else - { $PreviousC = How($ActualC) } - $Copied = 0 ; - if ($ActualA ne "") - { FlushSavedLine ; - print TUO "\\registerentrya{$Class}{$ActualA}\n" ; - $Copied = 1 } - if ($ActualB ne "") - { FlushSavedLine ; - print TUO "\\registerentryb{$Class}{$ActualB}\n" ; - $Copied = 1 } - if ($ActualC ne "") - { FlushSavedLine ; - print TUO "\\registerentryc{$Class}{$ActualC}\n" ; - $Copied = 1 } - if ($Copied) - { $NOfSaneEntries++ } - if ($RealPage eq 0) - { FlushSavedLine ; - print TUO "\\registersee{$Class}{$PageHow,$TextHow}{$SeeToo}{$Page}\n" ; - $LastPage = $Page ; - $LastRealPage = $RealPage } - else { -if (($SavedHow ne $PageHow) && ($PageHow ne "")) { - # last valid page attribute counts - $SavedHow = $PageHow ; -} - if (($Copied) || ! (($LastPage eq $Page) && ($LastRealPage eq $RealPage))) - { # print "$LastPage / $Page // $LastRealPage / $RealPage\n" ; - $NextEntry = "{$Class}{$PreviousA}{$PreviousB}{$PreviousC}{$PageHow,$TextHow}" ; - #~ $SavedLine = "{$Class}{$PageHow,$TextHow}{$Location}{$Page}{$RealPage}\n" ; - $SavedLine = "{$Class}{$SavedHow,$TextHow}{$Location}{$Page}{$RealPage}\n" ; - if ($RegisterState eq $RegStat{"f"}) - { FlushSavedLine ; - print TUO "\\registerfrom$SavedLine" } - elsif ($RegisterState eq $RegStat{"t"}) - { FlushSavedLine ; - print TUO "\\registerto$SavedLine" ; $SavedHow = '' ; } - else - { if ($CollapseEntries) - { if ($SavedEntry ne $NextEntry) - { $SavedFrom = $SavedLine } - else - { $SavedTo = $SavedLine } - $SavedEntry = $NextEntry } - else - { print TUO "\\registerpage$SavedLine" ; $SavedHow = '' ; } - } - ++$NOfSanePages ; - $LastPage = $Page ; - $LastRealPage = $RealPage } } } - -FlushSavedLine ; - - Report("RegisterEntries", $NOfEntries, "->", $NOfSaneEntries, "Entries", - $NOfSanePages, "References") ; - if ($NOfBadEntries>0) - { Report("RegisterErrors", $NOfBadEntries) } } - -#D As promised, we show the results: -#D -#D \plaatstestentry - -#D For debugging purposes we flush some status information. The -#D faster machines become, the more important this section will -#D be. The totals, when changed, force texexec to do a second pass. - -sub FlushData - { print TUO "%\n" . "% $Program / Status\n" . "%\n" ; - print TUO "" . - "% embedded files : $NOfFiles ($NOfBadFiles errors)\n" . - "% synonym entries : $NOfSynonyms ($NOfBadSynonyms errors)\n" . - "% register entries : $NOfEntries ($NOfBadEntries errors)\n" . - "% metapost graphics : $TotalNOfMPgraphics\n" . - "% position commands : $TotalNOfPositions " ; - if ($TotalNOfPositions) - { if ($NOfPositionsFound) - { print TUO "(resolved)\n" } - else - { print TUO "(unresolved)\n" } } - else - { print TUO "(not used)\n" } } - -#D The functionallity described on the previous few pages is -#D called upon in the main routine: - -sub NormalHandleReferences - { if ($InputFile eq "") - { Report("Error", "NoInputFile") } - else - { unless (open (TUI, "$InputFile.tui")) - { Report("Error", "EmptyInputFile", $InputFile) } - else - { Report("InputFile", "$InputFile.tui" ) ; - unlink "$InputFile.tmp" ; - rename "$InputFile.tuo", "$InputFile.tmp" ; - Report("OutputFile", "$InputFile.tuo" ) ; - open (TUO, ">$InputFile.tuo") ; - print TUO "%\n" . "% $Program / Commands\n" . "%\n" ; - while (<TUI>) - { $SomeLine = $_ ; - chomp $SomeLine ; - ($FirstTag, $RestOfLine) = split ' ', $SomeLine, 2 ; - if ($FirstTag eq "c") - { HandleCommand } - elsif ($FirstTag eq "s") - { HandleSynonym } - elsif ($FirstTag eq "r") - { HandleRegister } - elsif ($FirstTag eq "f") - { HandleFile } - elsif ($FirstTag eq "k") - { HandleKey } - elsif ($FirstTag eq "e") - { HandleExtra } - elsif ($FirstTag eq "p") - { HandlePlugIn } - elsif ($FirstTag eq "q") - { $ValidOutput = 0 ; - last } } - if ($ValidOutput) - { FlushCommands ; # already done during pass - FlushKeys ; - FlushRegisters ; - FlushSynonyms ; - FlushPlugIns ; - FlushFiles ; - FlushData ; - FlushExtra ; - close (TUO) ; - RunExtraPrograms } - else - { close (TUO) ; - unlink "$InputFile.tuo" ; - rename "$InputFile.tmp", "$InputFile.tuo" ; - Report ("Remark", "NoOutputFile") } } } } - -my $Suffix ; - -sub MergerHandleReferences - { unlink "texutil.tuo" ; - Report("OutputFile", "texutil.tuo" ) ; - open (TUO, ">texutil.tuo") ; - foreach $InputFile (@ARGV) - { ($InputFile, $Suffix) = split (/\./, $InputFile, 2) ; - unless (open (TUI, "$InputFile.tui")) - { Report("Error", "EmptyInputFile", $InputFile) } - else - { Report("InputFile", "$InputFile.tui" ) ; - while (<TUI>) - { $SomeLine = $_ ; - chomp $SomeLine ; - ($FirstTag, $RestOfLine) = split ' ', $SomeLine, 2 ; - if ($FirstTag eq "r") - { HandleRegister } } } } - if ($ValidOutput) - { FlushRegisters ; - close (TUO) } - else - { close (TUO) ; - unlink "texutil.tuo" ; - Report ("Remark", "NoOutputFile") } } - -# sub HandleReferences -# { Report("Action", "ProcessingReferences") ; -# if ($ProcessIJ ) -# { Report("Option", "SortingIJ") } -# if ($ProcessHigh) -# { Report("Option", "ConvertingHigh") } -# if ($ProcessQuotes) -# { Report("Option", "ProcessingQuotes") } -# if ($InputFile eq "") -# { Report("Error", "NoInputFile") } -# else -# { unless (open (TUI, "$InputFile.tui")) -# { Report("Error", "EmptyInputFile", $InputFile) } -# else -# { Report("InputFile", "$InputFile.tui" ) ; -# InitializeCommands ; -# InitializeRegisters ; -# InitializeSynonyms ; -# InitializeFiles ; -# $ValidOutput = 1 ; -# unlink "$InputFile.tmp" ; -# rename "$InputFile.tuo", "$InputFile.tmp" ; -# Report("OutputFile", "$InputFile.tuo" ) ; -# open (TUO, ">$InputFile.tuo") ; -# while (<TUI>) -# { $SomeLine = $_ ; -# chomp $SomeLine ; -# ($FirstTag, $RestOfLine) = split ' ', $SomeLine, 2 ; -# if ($FirstTag eq "c") -# { HandleCommand } -# elsif ($FirstTag eq "s") -# { HandleSynonym } -# elsif ($FirstTag eq "r") -# { HandleRegister } -# elsif ($FirstTag eq "f") -# { HandleFile } -# elsif ($FirstTag eq "q") -# { $ValidOutput = 0 ; -# last } } -# if ($ValidOutput) -# { FlushCommands ; # already done during pass -# FlushRegisters ; -# FlushSynonyms ; -# FlushFiles ; -# FlushData ; -# close (TUO) } -# else -# { close (TUO) ; -# unlink "$InputFile.tuo" ; -# rename "$InputFile.tmp", "$InputFile.tuo" ; -# Report ("Remark", "NoOutputFile") } } } } - -sub HandleReferences - { $Merging = @ARGV ; - $Merging = ($Merging>1) ; - if ($Merging) - { Report("Action", "MergingReferences") } - else - { Report("Action", "ProcessingReferences") } - if ($ProcessIJ ) - { Report("Option", "SortingIJ") } - if ($ProcessHigh) - { Report("Option", "ConvertingHigh") } - if ($ProcessQuotes) - { Report("Option", "ProcessingQuotes") } - InitializeKeys ; - InitializeCommands ; - InitializeExtra ; - InitializeRegisters ; - InitializeSynonyms ; - InitializeFiles ; - $ValidOutput = 1 ; - if ($Merging) - { MergerHandleReferences } - else - { NormalHandleReferences } } - -# moved to ctxtools -# -# sub HandleDocuments -# { my $files = @ARGV.join(' ') ; system("ctxtools $files") } - -#D \extras -#D {documents} -#D -#D Documentation can be woven into a source file. The next -#D routine generates a new, \TEX\ ready file with the -#D documentation and source fragments properly tagged. The -#D documentation is included as comment: -#D -#D \starttypen -#D %D ...... some kind of documentation -#D %M ...... macros needed for documenation -#D %S B begin skipping -#D %S E end skipping -#D \stoptypen -#D -#D The most important tag is \type{%D}. Both \TEX\ and -#D \METAPOST\ files use \type{%} as a comment chacacter, while -#D \PERL\ uses \type{#}. Therefore \type{#D} is also handled. -#D -#D The generated file gets the suffix \type{ted} and is -#D structured as: -#D -#D \starttypen -#D \startmodule[type=suffix] -#D \startdocumentation -#D \stopdocumentation -#D \startdefinition -#D \stopdefinition -#D \stopmodule -#D \stoptypen -#D -#D Macro definitions specific to the documentation are not -#D surrounded by start||stop commands. The suffix specifaction -#D can be overruled at runtime, but defaults to the file -#D extension. This specification can be used for language -#D depended verbatim typesetting. - -my $skippingbang = 0 ; - -sub HandleDocuments - { Report("Action", "GeneratingDocumentation") ; - if ($ProcessType ne "") - { Report("Option", "ForcingFileType", $ProcessType) } - if ($InputFile eq "") - { Report("Error", "NoInputFile") } - else - { CheckInputFiles ($InputFile) ; - foreach $FullName (@UserSuppliedFiles) - { ($FileName, $FileSuffix) = SplitFileName ($FullName) ; - unless ($FileSuffix) - { $FileSuffix = "tex" } - unless (-f "$FileName.$FileSuffix") - { next } - unless (open (TEX, "$FileName.$FileSuffix")) - { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) } - else - { Report("InputFile", "$FileName.$FileSuffix") ; - Report("OutputFile", "$FileName.ted") ; - open (TED, ">$FileName.ted") ; - $NOfDocuments = 0 ; - $NOfDefinitions = 0 ; - $NOfSkips = 0 ; - $SkipLevel = 0 ; - $InDocument = 0 ; - $InDefinition = 0 ; - $skippingbang = 0 ; - if ($ProcessType eq "") - { $FileType=lc $FileSuffix } - else - { $FileType=lc $ProcessType } - Report("FileType", $FileType) ; - # we need to signal to texexec what interfaec to use - my $firstline = <TEX> ; - if ($firstline =~ /^\%.*interface\=/) - { print TED $firstline } - else - { seek TEX, 0, 0 } - # so far - print TED "\\startmodule[type=$FileType]\n" ; - while (<TEX>) - { chomp ; - s/\s*$//o ; - if ($skippingbang) - { $skippingbang = 0 } - elsif (/^[%\#]D/) - { if ($SkipLevel == 0) - { if (length $_ < 3) - {$SomeLine = "" } - else # HH: added after that - {$SomeLine = substr $_, 3 } - if ($InDocument) - { print TED "$SomeLine\n" } - else - { if ($InDefinition) - { print TED "\\stopdefinition\n" ; - $InDefinition = 0 } - unless ($InDocument) - { print TED "\n\\startdocumentation\n" } - print TED "$SomeLine\n" ; - $InDocument = 1 ; - ++$NOfDocuments } } } - elsif (/^[%\#]M/) - { if ($SkipLevel == 0) - { $SomeLine = substr $_, 3 ; - print TED "$SomeLine\n" } } - elsif (/^[%\%]S B]/) - { ++$SkipLevel ; - ++$NOfSkips } - elsif (/^[%\%]S E]/) - { --$SkipLevel } - elsif (/^[%\#]/) - { } - elsif (/^eval \'\(exit \$\?0\)\' \&\& eval \'exec perl/o) - { $skippingbang = 1 } - elsif ($SkipLevel == 0) - { $InLocalDocument = $InDocument ; - $SomeLine = $_ ; - if ($InDocument) - { print TED "\\stopdocumentation\n" ; - $InDocument = 0 } - if (($SomeLine eq "") && ($InDefinition)) - { print TED "\\stopdefinition\n" ; - $InDefinition = 0 } - else - { if ($InDefinition) - { print TED "$SomeLine\n" } - elsif ($SomeLine ne "") - { print TED "\n" . "\\startdefinition\n" ; - $InDefinition = 1 ; - unless ($InLocalDocument) - { ++$NOfDefinitions } - print TED "$SomeLine\n" } } } } - if ($InDocument) - { print TED "\\stopdocumentation\n" } - if ($InDefinition) - { print TED "\\stopdefinition\n" } - print TED "\\stopmodule\n" ; - close (TED) ; - unless (($NOfDocuments) || ($NOfDefinitions)) - { unlink "$FileName.ted" } - Report ("NOfDocuments", $NOfDocuments) ; - Report ("NOfDefinitions", $NOfDefinitions) ; - Report ("NOfSkips", $NOfSkips) } } } } - -#D \extras -#D {sources} -#D -#D Documented sources can be stripped of documentation and -#D comments, although at the current processing speeds the -#D overhead of skipping the documentation at run time is -#D neglectable. Only lines beginning with a \type{%} are -#D stripped. The stripped files gets the suffix \type{tes}. - -sub HandleSources - { Report("Action", "GeneratingSources") ; - if ($InputFile eq "") - { Report("Error", "NoInputFile") } - else - { CheckInputFiles ($InputFile) ; - foreach $FullName (@UserSuppliedFiles) - { ($FileName, $FileSuffix) = SplitFileName ($FullName) ; - unless ($FileSuffix) - { $FileSuffix = "tex" } - unless (-f "$FileName.$FileSuffix") - { next } - unless (open (TEX, "$FileName.$FileSuffix")) - { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) } - else - { Report("InputFile", "$FileName.$FileSuffix") ; - Report("OutputFile", "$FileName.tes") ; - open (TES, ">$FileName.tes") ; - $EmptyLineDone = 1 ; - $FirstCommentDone = 0 ; - while (<TEX>) - { $SomeLine = $_ ; - chomp $SomeLine ; - if ($SomeLine eq "") - { unless ($FirstCommentDone) - { $FirstCommentDone = 1 ; - print TES - "\n% further documentation is removed\n\n" ; - $EmptyLineDone = 1 } - unless ($EmptyLineDone) - { print TES "\n" ; - $EmptyLineDone = 1 } } - elsif ($SomeLine =~ /^%/) - { unless ($FirstCommentDone) - { print TES "$SomeLine\n" ; - $EmptyLineDone = 0 } } - else - { print TES "$SomeLine\n" ; - $EmptyLineDone = 0 } } - close (TES) ; - unless ($FirstCommentDone) - { unlink "$FileName.tes" } } } } } - -#D \extras -#D {setups} -#D -#D All \CONTEXT\ commands are specified in a compact format -#D that can be used to generate quick reference tables and -#D cards. Such setups are preceded by \type{%S}. The setups -#D are collected in the file \type{texutil.tus}. - -sub HandleSetups - { Report("Action", "FilteringDefinitions" ) ; - if ($InputFile eq "") - { Report("Error", "NoInputFile") } - else - { SetOutputFile ("texutil.tus" ) ; - Report("OutputFile", $OutputFile) ; - open (TUS, ">$OutputFile") ; # always reset! - $NOfSetups = 0 ; - CheckInputFiles ($InputFile) ; - foreach $FullName (@UserSuppliedFiles) - { ($FileName, $FileSuffix) = SplitFileName ($FullName) ; - unless ($FileSuffix) - { $FileSuffix = "tex" } - unless (-f "$FileName.$FileSuffix") - { next } - unless (open (TEX, "$FileName.$FileSuffix")) - { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) } - else - { Report("InputFile", "$FileName.$FileSuffix") ; - print TUS "%\n" . "% File : $FileName.$FileSuffix\n" . "%\n" ; - while (<TEX>) - { $SomeLine = $_ ; - chomp $SomeLine ; - ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) ; - if ($Tag eq "%S") - { ++$NOfSetups ; - while ($Tag eq "%S") - { print TUS "$RestOfLine\n" ; - $SomeLine = <TEX> ; - chomp $SomeLine ; - ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) } - print TUS "\n" } } } } - close (TUS) ; - unless ($NOfSetups) - { unlink $OutputFile } - Report("NOfSetups", $NOfSetups) } } - -#D \extras -#D {templates, infos} -#D -#D From the beginning, the \CONTEXT\ source files contained -#D helpinfo and key||templates for \TEXEDIT. In fact, for a -#D long time, this was the only documentation present. More -#D and more typeset (interactive) documentation is replacing -#D this helpinfo, but we still support the traditional method. -#D This information is formatted like: -#D -#D \starttypen -#D %I n=Struts -#D %I c=\strut,\setnostrut,\setstrut,\toonstruts -#D %I -#D %I text -#D %I .... -#D %P -#D %I text -#D %I .... -#D \stoptypen -#D -#D Templates look like: -#D -#D \starttypen -#D %T n=kap -#D %T m=kap -#D %T a=k -#D %T -#D %T \kap{?} -#D \stoptypen -#D -#D The key||value pairs stand for {\em name}, {\em mnemonic}, -#D {\em key}. This information is copied to files with the -#D extension \type{tud}. - -sub HandleEditorCues - { if ($ProcessTemplates) - { Report("Action", "CopyingTemplates" ) } - if ($ProcessInfos) - {Report("Action", "CopyingInformation" ) } - if ($InputFile eq "") - { Report("Error", "NoInputFile") } - else - { CheckInputFiles ($InputFile) ; - foreach $FullName (@UserSuppliedFiles) - { ($FileName, $FileSuffix) = SplitFileName ($FullName) ; - if ($FileSuffix eq "") - { $FileSuffix = "tex" } - unless (-f "$FileName.$FileSuffix") - { next } - unless (open (TEX, "$FileName.$FileSuffix")) - { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) } - else - { Report("InputFile", "$FileName.$FileSuffix") ; - Report("OutputFile", "$FileName.tud") ; - open (TUD, ">$FileName.tud") ; - $NOfTemplates = 0 ; - $NOfInfos = 0 ; - while (<TEX>) - { $SomeLine = $_ ; - chomp $SomeLine ; - ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) ; - if (($Tag eq "%T") && ($ProcessTemplates)) - { ++$NOfTemplates ; - while ($Tag eq "%T") - { print TUD "$SomeLine\n" ; - $SomeLine = <TEX> ; - chomp $SomeLine ; - ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) } - print TUD "\n" } - elsif (($Tag eq "%I") && ($ProcessInfos)) - { ++$NOfInfos ; - while (($Tag eq "%I") || ($Tag eq "%P")) - { print TUD "$SomeLine\n" ; - $SomeLine = <TEX> ; - chomp $SomeLine ; - ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) } - print TUD "\n" } } - close (TUD) ; - unless (($NOfTemplates) || ($NOfInfos)) - { unlink "$FileName.tud" } - if ($ProcessTemplates) - { Report("NOfTemplates", $NOfTemplates) } - if ($ProcessInfos) - { Report("NOfInfos", $NOfInfos) } } } } } - -#D \extras -#D {figures} -#D -#D Directories can be scanned for illustrations in \EPS, \PDF, -#D \TIFF, \PNG\ or \JPG\ format. The resulting file \type{texutil.tuf} -#D contains entries like: -#D -#D \starttypen -#D \thisisfigureversion{year.month.day} -#D \presetfigure[file][...specifications...] -#D \stoptypen -#D -#D where the specifications are: -#D -#D \starttypen -#D [e=suffix,x=xoffset,y=yoffset,w=width,h=height,t=title,c=creator,s=size] -#D \stoptypen -#D -#D This data can be used when determining dimensions and -#D generate directories of illustrations. - -$DPtoCM = 2.54/72.0 ; -$INtoCM = 2.54 ; - -sub SaveFigurePresets - { my ($FNam, $FTyp, $FUni, $FXof, $FYof, $FWid, $FHei, $FTit, $FCre, $FSiz) = @_ ; - if ($ProcessVerbose) - { OpenTerminal ; - if ($FUni) - { print "n=$FNam t=$FTyp " . - (sprintf "x=%1.3fcm y=%1.3fcm ", $FXof, $FYof) . - (sprintf "w=%5.3fcm h=%5.3fcm\n", $FWid, $FHei) } - else - { print "n=$FNam t=$FTyp " . - "x=${FXof}bp y=${FYof}bp " . - "w=${FWid}bp h=${FHei}bp\n" } - CloseTerminal } - else - { ++$NOfFigures ; - $Figures[$NOfFigures] = "\\presetfigure[$FNam][e=$FTyp" ; - if ($FUni) - { $Figures[$NOfFigures] .= (sprintf ",w=%5.3fcm,h=%5.3fcm", $FWid, $FHei) } - else - { $Figures[$NOfFigures] .= ",w=${FWid}bp,h=${FHei}bp" } - if (($FXof!=0)||($FYof!=0)) - { if ($FUni) - { $Figures[$NOfFigures] .= (sprintf ",x=%1.3fcm,y=%1.3fcm", $FXof, $FYof) } - else - { $Figures[$NOfFigures] .= ",x=${FXof}bp,y=${FYof}bp" } } - if ($FTit) - { $Figures[$NOfFigures] .= ",t=\{$FTit\}" } - if ($FCre) - { $Figures[$NOfFigures] .= ",c=\{$FCre\}" } - $Figures[$NOfFigures] .= ",s=$FSiz]" } } - -#D The \EPS\ to \PDF\ conversion pipe to \GHOSTSCRIPT\ is -#D inspired by a script posted by Sebastian Ratz at the -#D \PDFTEX\ mailing list. Watch the bounding box check, we -#D use the values found in an earlier pass. - -sub ConvertEpsToEps - { my ( $SuppliedFileName , $LLX, $LLY, $URX, $URY ) = @_ ; - ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ; - if ($ProcessEpsToPdf) - { if ($dosish) { $gs = "gswin32c" } else { $gs = "gs" } - unlink "$FileName.pdf" ; - $GSCommandLine = "-q " . - "-sDEVICE=pdfwrite " . - "-dNOCACHE " . - "-dUseFlateCompression=true " . - "-dMaxSubsetPct=100 " . - "-sOutputFile=$FileName.pdf " . - "- -c " . - "quit " ; - open ( EPS, "| $gs $GSCommandLine") } - elsif ($PDFReady) - { return } - else - { open ( EPS, ">texutil.tmp" ) ; - binmode EPS } - open ( TMP , "$SuppliedFileName" ) ; - binmode TMP ; - $EpsBBOX = 0 ; - $EpsWidth = $URX - $LLX ; - $EpsHeight = $URY - $LLY ; - $EpsXOffset = 0 - $LLX ; - $EpsYOffset = 0 - $LLY ; - while (<TMP>) - { if (/%!PS/) - { s/(.*)%!PS/%!PS/o ; - print EPS $_ ; - last } } - while (<TMP>) - { if ((!$PDFReady)&&(/^%%(HiResB|ExactB|B)oundingBox:/o)) - { unless ($EpsBBOX) - { print EPS "%%PDFready: $Program\n" ; - print EPS "%%BoundingBox: 0 0 $EpsWidth $EpsHeight\n" ; - print EPS "<< /PageSize [$EpsWidth $EpsHeight] >> setpagedevice\n" ; - print EPS "gsave $EpsXOffset $EpsYOffset translate\n" ; - $EpsBBOX = 1 } } - elsif (/^%%EOF/o) # when final: (/^%%(EOF|Trailer)/o) - { last } - elsif (/^%%Trailer/o) - { last } - else - { print EPS $_ } } - close ( TMP ) ; - if (($EpsBBOX)&&(!$PDFReady)) - { print EPS "grestore\n%%EOF\n%%RestOfFileIgnored: $Program\n" ; - close ( EPS ) ; - Report ( "PdfFile", "$SuppliedFileName" ) ; - unless ($ProcessEpsToPdf) - { unlink "$SuppliedFileName" ; - rename "texutil.tmp", "$SuppliedFileName" } } - else - { close (EPS) } - unlink "texutil.tmp" } - -sub HandleEpsFigure - { my ($SuppliedFileName) = @_ ; - my ($Temp) = "" ; - if (-f $SuppliedFileName) - { ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ; - if ($FileSuffix ne "") - {#$Temp = $FileSuffix ; - #$Temp =~ s/[0-9]//go ; - #if ($Temp eq "") - if ($FileSuffix =~ /^[0-9]+$/o) - { $EpsFileName = $SuppliedFileName; - Report ( "MPFile", "$SuppliedFileName" ) } - elsif ((lc $FileSuffix ne "eps")&&(lc $FileSuffix ne "mps")) - { return } - else - { $EpsFileName = $SuppliedFileName; # $FileName - Report ( "EpsFile", "$SuppliedFileName" ) } - $EpsTitle = "" ; - $EpsCreator = "" ; - open ( EPS , $SuppliedFileName ) ; - binmode EPS ; - $EpsSize = -s EPS ; - $PDFReady = 0 ; - $MPSFound = 0 ; - $BBoxFound = 0 ; - while (<EPS>) - { $SomeLine = $_; - chomp $SomeLine ; - if (($BBoxFound) && ((substr $SomeLine,0,1) ne "%")) - { last } - if ($BBoxFound<2) - { if ($SomeLine =~ /^%%BoundingBox:(?!\s+\(atend\))/io) # atend (th) - { $EpsBBox = $SomeLine ; $BBoxFound = 1 ; next } - elsif ($SomeLine =~ /^%%HiResBoundingBox:/io) - { $EpsBBox = $SomeLine ; $BBoxFound = 2 ; next } - elsif ($SomeLine =~ /^%%ExactBoundingBox:/io) - { $EpsBBox = $SomeLine ; $BBoxFound = 3 ; next } } - if ($SomeLine =~ /^%%PDFready:/io) - { $PDFReady = 1 } - elsif ($SomeLine =~ /^%%Creator:/io) - { ($Tag, $EpsCreator) = split (/ /, $SomeLine, 2) ; - if ($EpsCreator =~ /MetaPost/io) - { $MPSFound = 1 } } - elsif ($SomeLine =~ /^%%Title:/io) - { ($Tag, $EpsTitle) = split (/ /, $SomeLine, 2) } } - close ( EPS ) ; - if ($BBoxFound) - { ($Tag, $LLX, $LLY, $URX, $URY, $RestOfLine) = split (/ /, $EpsBBox, 6 ) ; - $EpsHeight = ($URY-$LLY)*$DPtoCM ; - $EpsWidth = ($URX-$LLX)*$DPtoCM ; - $EpsXOffset = $LLX*$DPtoCM ; - $EpsYOffset = $LLY*$DPtoCM ; - if ($MPSFound) - { $EpsType = "mps" } - else - { $EpsType = "eps" } - SaveFigurePresets - ( $EpsFileName, $EpsType, 1, - $EpsXOffset, $EpsYOffset, $EpsWidth, $EpsHeight, - $EpsTitle, $EpsCreator, $EpsSize ) ; - if (($ProcessEpsPage) || ($ProcessEpsToPdf)) - { ConvertEpsToEps ( $SuppliedFileName, $LLX, $LLY, $URX, $URY ) } } - else - { Report ( "MissingBoundingBox", "$SuppliedFileName" ) } } } } - -#D The \PDF\ scanning does a similar job. This time we -#D search for a mediabox. I could have shared some lines -#D with the previous routines, but prefer readability. - -sub HandlePdfFigure - { my ( $SuppliedFileName ) = @_ ; - ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ; - if (lc $FileSuffix ne "pdf") - { return } - else - { $PdfFileName = $SuppliedFileName ; - Report ( "PdfFile", "$SuppliedFileName" ) } - open ( PDF , $SuppliedFileName ) ; - binmode PDF ; - $PdfSize = -s PDF ; - $MediaBoxFound = 0 ; - $MediaBox = 0 ; - $PageFound = 0 ; - $PagesFound = 0 ; - while (<PDF>) - { $SomeLine = $_ ; - chomp ($SomeLine) ; - if ($SomeLine =~ /\/Type\s*\/Pages/io) - { $PagesFound = 1 } - elsif ($SomeLine =~ /\/Type\s*\/Page/io) - { ++$PageFound ; - if ($PageFound>1) { last } } - if (($PageFound)||($PagesFound)) - { if (($MediaBoxFound < 2) && ($SomeLine =~ /\/ArtBox\s*\[/io)) - { $MediaBoxFound = 3 ; - $MediaBox = $SomeLine } - elsif (($MediaBoxFound < 2) && ($SomeLine =~ /\/CropBox\s*\[/io)) - { $MediaBoxFound = 2 ; - $MediaBox = $SomeLine } - elsif (($MediaBoxFound == 0) && ($SomeLine =~ /\/MediaBox\s*\[/io)) - { $MediaBoxFound = 1 ; - $MediaBox = $SomeLine } } } - close ( PDF ) ; - if ($PageFound>1) - { Report ( "MultiPagePdfFile", "$SuppliedFileName" ) } - if (($MediaBoxFound) && ($MediaBox)) - { my $D = "[0-9\-\.]" ; - $MediaBox =~ /\/(Media|Crop|Art)Box\s*\[\s*($D+)\s*($D+)\s*($D+)\s*($D+)/o ; - $LLX = $2 ; $LLY = $3 ; $URX = $4 ; $URY = $5 ; - $PdfHeight = ($URY-$LLY)*$DPtoCM ; - $PdfWidth = ($URX-$LLX)*$DPtoCM ; - $PdfXOffset = $LLX*$DPtoCM ; - $PdfYOffset = $LLY*$DPtoCM ; - SaveFigurePresets - ( $PdfFileName, "pdf", 1, - $PdfXOffset, $PdfYOffset, $PdfWidth, $PdfHeight, - "", "", $PdfSize ) } - else - { Report ( "MissingMediaBox", "$SuppliedFileName" ) } } - -#D A previous version of \TEXUTIL\ used \type{tifftags} or -#D \type{tiffinfo} for collecting the dimensions. However, -#D the current implementation does this job itself. - -sub TifGetByte - { my $B = 0 ; - read TIF, $B, 1 ; - return ord($B) } - -sub TifGetShort - { my $S = 0 ; - read TIF, $S, 2 ; - if ($TifLittleEndian) - { return (unpack ("v", $S)) } - else - { return (unpack ("n", $S)) } } - -sub TifGetLong - { my $L = 0 ; - read TIF, $L, 4 ; - if ($TifLittleEndian) - { return (unpack ("V", $L)) } - else - { return (unpack ("N", $L)) } } - -sub TifGetRational - { my ($N, $M) = (0,0) ; - $N = TifGetLong ; - $M = TifGetLong ; - return $N/$M } - -sub TifGetAscii - { my $S = "" ; - --$TifValues; - unless ($TifValues) - { return "" } - else - { read TIF, $S, $TifValues ; - return $S } } - -sub TifGetWhatever - { if ($_[0]==1) - { return TifGetByte } - elsif ($_[0]==2) - { return TifGetAscii } - elsif ($_[0]==3) - { return TifGetShort } - elsif ($_[0]==4) - { return TifGetLong } - elsif ($_[0]==5) - { return TifGetRational } - else - { return 0 } } - -sub TifGetChunk - { seek TIF, $TifNextChunk, 0 ; - $Length = TifGetShort ; - $TifNextChunk += 2 ; - for ($i=1; $i<=$Length; $i++) - { seek TIF, $TifNextChunk, 0 ; - $TifTag = TifGetShort ; - $TifType = TifGetShort ; - $TifValues = TifGetLong ; - if ($TifTag==256) - { $TifWidth = TifGetWhatever($TifType) } - elsif ($TifTag==257) - { $TifHeight = TifGetWhatever($TifType) } - elsif ($TifTag==296) - { $TifUnit = TifGetWhatever($TifType) } - elsif ($TifTag==282) - { seek TIF, TifGetLong, 0 ; - $TifHRes = TifGetWhatever($TifType) } - elsif ($TifTag==283) - { seek TIF, TifGetLong, 0 ; - $TifVRes = TifGetWhatever($TifType) } - elsif ($TifTag==350) - { seek TIF, TifGetLong, 0 ; - $TifCreator = TifGetWhatever($TifType) } - elsif ($TifTag==315) - { seek TIF, TifGetLong, 0 ; - $TifAuthor = TifGetWhatever($TifType) } - elsif ($TifTag==269) - { seek TIF, TifGetLong, 0 ; - $TifTitle = TifGetWhatever($TifType) } - $TifNextChunk += 12 } - seek TIF, $TifNextChunk, 0 ; - $TifNextChunk = TifGetLong ; - return ($TifNextChunk>0) } - -sub HandleTifFigure - { my ( $SuppliedFileName ) = @_ ; - ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ; - if (lc $FileSuffix ne "tif") - { return } - else - { $TifFile = $SuppliedFileName ; - if (open ( TIF, $TifFile )) { # { must be here, perl 5.003 bug - Report ( "TifFile", "$SuppliedFileName" ) ; - binmode TIF; - $TifWidth = 0 ; - $TifHeight = 0 ; - $TifTitle = "" ; - $TifAuthor = "" ; - $TifCreator = "" ; - $TifUnit = 0 ; - $TifHRes = 1 ; - $TifVRes = 1 ; - $TifSize = -s TIF ; - $TifByteOrder = "" ; - seek TIF, 0, 0 ; - read TIF, $TifByteOrder, 2 ; - $TifLittleEndian = ($TifByteOrder eq "II") ; - $TifTag = TifGetShort; - unless ($TifTag == 42) - { close ( TIF ) ; - return } - $TifNextChunk = TifGetLong ; - while (TifGetChunk) { } - if ($TifUnit==2) - { $TifMult = $INtoCM } - elsif ($TifUnit==3) - { $TifMult = 1 } - else - { $TifMult = 72 } - $TifWidth = ($TifWidth /$TifHRes)*$TifMult ; - $TifHeight = ($TifHeight/$TifVRes)*$TifMult ; - close ( TIF ) ; - SaveFigurePresets - ( $TifFile, "tif", $TifUnit, - 0, 0, $TifWidth, $TifHeight, - $TifTitle, $TifCreator, $TifSize ) } } } - -#D I first intended to use the public utility \type{pngmeta} -#D (many thanks to Taco for compiling it), but using this -#D utility to analyze lots of \PNG\ files, I tried to do a -#D similar job in \PERL. Here are the results: - -my ($PngSize, $PngWidth, $PngHeight) = (0,0,0) ; -my ($PngMult, $PngHRes, $PngVRes, $PngUnit) = (0,1,1,0) ; -my ($PngFile, $PngTitle, $PngAuthor, $PngCreator) = ("","","") ; -my ($PngNextChunk, $PngLength, $PngType) = (0,0,0) ; -my ($PngKeyword, $PngDummy) = ("","") ; - -my $PngSignature = chr(137) . chr(80) . chr(78) . chr(71) . - chr (13) . chr(10) . chr(26) . chr(10) ; -sub PngGetByte - { my ($B) = 0 ; - read PNG, $B, 1 ; - return (ord($B)) } - -sub PngGetLong - { my ($L) = 0 ; - read PNG, $L, 4 ; - return (unpack("N", $L)) } - -sub PngGetChunk - { if ($PngNextChunk<$PngSize) - { seek PNG, $PngNextChunk, 0 ; - $PngLength = PngGetLong ; - $PngNextChunk = $PngNextChunk + $PngLength + 12 ; - read PNG, $PngType, 4 ; - if ($PngType eq "") - { return 0 } - elsif ($PngType eq "IEND") - { return 0 } - elsif ($PngType eq "IHDR") - { $PngWidth = PngGetLong ; - $PngHeight = PngGetLong } - elsif ($PngType eq "pHYs") - { $PngHRes = PngGetLong ; - $PngVRes = PngGetLong ; - read PNG, $PngUnit, 1 } - elsif ($PngType eq "tEXt") - { read PNG, $PngKeyword, $PngLength ; - ($PngKeyword,$PngDummy) = split(/\x00/,$PngKeyword) ; - if ( $PngKeyword eq "Title") - { $PngTitle = $PngDummy } - elsif ( $PngKeyword eq "Author") - { $PngAuthor = $PngDummy } - elsif ( $PngKeyword eq "Software") - { $PngCreator = $PngDummy } } - return 1 } - else - { return 0 } } - -sub HandlePngFigure - { my ( $SuppliedFileName ) = @_ ; - ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ; - if (lc $FileSuffix ne "png") - { return } - else - { $PngFile = $SuppliedFileName ; - if (open ( PNG, $PngFile )) - { Report ( "PngFile", "$SuppliedFileName" ) } - $PngSize = 0 ; - $PngWidth = 0 ; - $PngHeight = 0 ; - $PngTitle = "" ; - $PngAuthor = "" ; - $PngCreator = "" ; - $PngUnit = 0 ; - $PngVRes = 1 ; - $PngHRes = 1 ; - $PngSig = "" ; - $PngSize = -s PNG ; - binmode PNG ; - seek PNG, 0, 0 ; - read PNG, $PngSig, 8; - unless ($PngSig eq $PngSignature) - { close ( PNG ) ; - return } - $PngNextChunk = 8 ; - while (PngGetChunk) { } - $PngWidth = ($PngWidth /$PngVRes) ; - $PngHeight = ($PngHeight/$PngHRes) ; - close ( PNG ) ; - SaveFigurePresets - ( $PngFile, "png", $PngUnit, - 0, 0, $PngWidth, $PngHeight, - $PngTitle, $PngCreator, $PngSize ) } } - -#D Well, we also offer \JPG\ scanning (actually \JFIF) -#D scanning. (I can recomend David Salomon's book on Data -#D Compression to those interested in the internals of -#D \JPG.) -#D -#D It took me some time to discover that the (sort of) -#D reference document I used had a faulty byte position table. -#D Nevertheless, when I was finaly able to grab the header, -#D Piet van Oostrum pointer me to the \PERL\ script of Alex -#D Knowles (and numerous other contributers), from which I -#D could deduce what segment contained the dimensions. - -my ($JpgSize, $JpgWidth, $JpgHeight) = (0,0,0) ; -my ($JpgMult, $JpgUnit, $JpgHRes, $JpgVRes) = (1,0,1,1) ; -my ($JpgFile, $JpgVersion, $JpgDummy) = ("",0,"") ; -my ($JpgSig, $JpgPos, $JpgLen, $JpgSoi, $JpgApp) = ("",0,0,0,0) ; - -my $JpgSignature = "JFIF" . chr(0) ; - -sub JpgGetByte - { my ($B) = 0 ; - read JPG, $B, 1 ; - return ( ord($B) ) } - -sub JpgGetInteger - { my ($I) = 0 ; - read JPG, $I, 2 ; - return (unpack("n", $I)) } - -sub HandleJpgFigure - { my ($SuppliedFileName) = @_ ; - ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ; - if (lc $FileSuffix ne "jpg") - { return } - else - { $JpgFile = $SuppliedFileName ; - Report ( "JpgFile", "$SuppliedFileName" ) } - open ( JPG, $JpgFile ) ; - binmode JPG ; - $JpgSignature = "JFIF" . chr(0) ; - $JpgSize = -s JPG ; - $JpgWidth = 0 ; - $JpgHeight = 0 ; - $JpgUnit = 0 ; - $JpgVRes = 1 ; - $JpgHRes = 1 ; - seek JPG, 0, 0 ; - read JPG, $JpgSig, 4 ; - unless ($JpgSig eq chr(255).chr(216).chr(255).chr(224)) - { close ( JPG ) ; - return } - $JpgLen = JpgGetInteger; - read JPG, $JpgSig, 5 ; - unless ($JpgSig eq $JpgSignature) - { close ( JPG ) ; - return } - $JpgUnit = JpgGetByte ; - $JpgVersion = JpgGetInteger ; - $JpgHRes = JpgGetInteger ; - $JpgVRes = JpgGetInteger ; - $JpgPos = $JpgLen + 4 ; - $JpgSoi = 255 ; - while () - { seek JPG, $JpgPos, 0 ; - $JpgSoi = JpgGetByte ; - $JpgApp = JpgGetByte ; - $JpgLen = JpgGetInteger ; - if ($JpgSoi!=255) - { last } - if (($JpgApp>=192) && ($JpgApp<=195)) # Found in the perl script. - { $JpgDummy = JpgGetByte ; # Found in the perl script. - $JpgHeight = JpgGetInteger ; # Found in the perl script. - $JpgWidth = JpgGetInteger } # Found in the perl script. - $JpgPos = $JpgPos + $JpgLen + 2 } - close ( JPG ) ; - if ($JpgUnit==1) - { $JpgMult = $INtoCM } - else - { $JpgMult = 1 } - $JpgHRes = 72 unless $JpgHRes>1 ; - $JpgVRes = 72 unless $JpgVRes>1 ; - $JpgWidth = ($JpgWidth/$JpgHRes)*$JpgMult ; - $JpgHeight = ($JpgHeight/$JpgVRes)*$JpgMult ; - close ( JPG ) ; - SaveFigurePresets - ( $JpgFile, "jpg", $JpgUnit, - 0, 0, $JpgWidth, $JpgHeight, - "", "", $JpgSize ) } - -#D Now we can handle figures! - -sub InitializeFigures - { $NOfFigures = 0 } - -sub FlushFigures - { SetOutputFile ("texutil.tuf") ; - open ( TUF, ">$OutputFile" ) ; - print TUF "%\n" . "% $Program / Figures\n" . "%\n" ; - print TUF "\\thisisfigureversion\{1996.06.01\}\n" . "%\n" ; - # a joins is nicer - for ($n=1 ; $n<=$NOfFigures ; ++$n) - { print TUF "$Figures[$n]%\n" } - print TUF "\\endinput"; - close (TUF) ; - if ($NOfFigures) - { Report("OutputFile", $OutputFile ) } - else - { unlink $OutputFile } - Report ( "NOfFigures", $NOfFigures ) } - -sub DoHandleFigures - { my ($FigureSuffix, $FigureMethod) = @_ ; - if ($InputFile eq "") - { $InputFile = $FigureSuffix } - CheckInputFiles ($InputFile) ; - foreach $FileName (@UserSuppliedFiles) - { &{$FigureMethod} ( $FileName ) } } - -sub HandleFigures - { Report("Action", "GeneratingFigures" ) ; - foreach $FileType (@ARGV) - { if ($FileType=~/\.eps/io) - { Report("Option", "UsingEps") ; - if ($ProcessEpsToPdf) { Report("Option", "EpsToPdf") } - if ($ProcessEpsPage) { Report("Option", "EpsPage") } - last } } - foreach $FileType (@ARGV) - { if ($FileType=~/\.pdf/io) - { Report("Option", "UsingPdf") ; - last } } - foreach $FileType (@ARGV) - { if ($FileType=~/\.tif/io) - { Report("Option", "UsingTif") ; - #RunTifPrograms ; - last } } - foreach $FileType (@ARGV) - { if ($FileType=~/\.png/io) - { Report("Option", "UsingPng") ; - last } } - foreach $FileType (@ARGV) - { if ($FileType=~/\.jpg/io) - { Report("Option", "UsingJpg") ; - last } } - InitializeFigures ; - DoHandleFigures ("eps", "HandleEpsFigure") ; - DoHandleFigures ("pdf", "HandlePdfFigure") ; - DoHandleFigures ("tif", "HandleTifFigure") ; - DoHandleFigures ("png", "HandlePngFigure") ; - DoHandleFigures ("jpg", "HandleJpgFigure") ; - FlushFigures } - -#D \extras -#D {logfiles} -#D -#D This (poor man's) log file scanning routine filters -#D overfull box messages from a log file (\type{\hbox}, -#D \type{\vbox} or both). The collected problems are saved -#D in \type{$ProgramLog}. One can specify a selection -#D criterium. -#D -#D \CONTEXT\ reports unknown entities. These can also be -#D filtered. When using fast computers, or when processing -#D files in batch, one has to rely on the log files and/or -#D this filter. - -$Unknown = "onbekende verwijzing|" . - "unbekannte Referenz|" . - "unknown reference|" . - "dubbele verwijzing|" . - "duplicate reference|" . - "doppelte Referenz" ; - -sub FlushLogTopic - { unless ($TopicFound) - { $TopicFound = 1 ; - print ALL "\n% File: $FileName.log\n\n" } } - -sub HandleLogFile - { if ($ProcessBox) - { Report("Option", "FilteringBoxes", "(\\vbox & \\hbox)") ; - $Key = "[h|v]box" } - elsif ($ProcessHBox) - { Report("Option", "FilteringBoxes", "(\\hbox)") ; - $Key = "hbox" ; - $ProcessBox = 1 } - elsif ($ProcessVBox) - { Report("Option", "FilteringBoxes", "(\\vbox)") ; - $Key = "vbox" ; - $ProcessBox = 1 } - if (($ProcessBox) && ($ProcessCriterium)) - { Report("Option", "ApplyingCriterium") } - if ($ProcessUnknown) - { Report("Option", "FilteringUnknown") } - unless (($ProcessBox) || ($ProcessUnknown)) - { ShowHelpInfo ; - return } - Report("Action", "FilteringLogFile" ) ; - if ($InputFile eq "") - { Report("Error", "NoInputFile") } - else - { $NOfBoxes = 0 ; - $NOfMatching = 0 ; - $NOfUnknown = 0 ; - SetOutputFile ($ProgramLog) ; - Report("OutputFile", $OutputFile) ; - CheckInputFiles ($InputFile) ; - open ( ALL, ">$OutputFile" ) ; - foreach $FullName (@UserSuppliedFiles) - { ($FileName, $FileSuffix) = SplitFileName ($FullName) ; - if (! open (LOG, "$FileName.log")) - { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) } - elsif (-e "$FileName.tex") - { $TopicFound = 0 ; - Report("InputFile", "$FileName.log") ; - while (<LOG>) - { $SomeLine = $_ ; - chomp $SomeLine ; - if (($ProcessBox) && ($SomeLine =~ /Overfull \\$Key/)) - { ++$NOfBoxes ; - $SomePoints = $SomeLine ; - $SomePoints =~ s/.*\((.*)pt.*/$1/ ; - if ($SomePoints>=$ProcessCriterium) - { ++$NOfMatching ; - FlushLogTopic ; - print ALL "$SomeLine\n" ; - $SomeLine=<LOG> ; - print ALL $SomeLine } } - if (($ProcessUnknown) && ($SomeLine =~ /$Unknown/io)) - { ++$NOfUnknown ; - FlushLogTopic ; - print ALL "$SomeLine\n" } } } } - close (ALL) ; - unless (($NOfBoxes) ||($NOfUnknown)) - { unlink $OutputFile } - if ($ProcessBox) - { Report ( "NOfBoxes" , "$NOfBoxes", "->", $NOfMatching, "Overfull") } - if ($ProcessUnknown) - { Report ( "NOfUnknown", "$NOfUnknown") } } } - -#D Undocumented feature. -# -# obsolete, i.e now in ctxtools, so this will become: -# -# sub PurgeFiles { -# if ($PurgeAllFiles) { -# system("ctxtools --purge $ARGV[0]") ; -# } else { -# system("ctxtools --purge --all $ARGV[0]") ; -# } - -my $removedfiles = 0 ; -my $keptfiles = 0 ; -my $persistentfiles = 0 ; -my $reclaimedbytes = 0 ; - -sub RemoveContextFile - { my $filename = shift ; - my $filesize = -s $filename ; - unlink $filename ; - if (-e $filename) - { ++$persistentfiles ; - print " persistent : $filename\n" } - else - { ++$removedfiles ; $reclaimedbytes += $filesize ; - print " removed : $filename\n" } } - -sub KeepContextFile - { my $filename = shift ; - ++$keptfiles ; - print " kept : $filename\n" } - -my @dontaskprefixes = sort glob "mpx-*" ; push @dontaskprefixes , - ("tex-form.tex","tex-edit.tex","tex-temp.tex", - "texexec.tex","texexec.tui","texexec.tuo", - "texexec.ps","texexec.pdf","texexec.dvi", - "cont-opt.tex","cont-opt.bak") ; -my @dontasksuffixes = - ("mpgraph.mp","mpgraph.mpd","mpgraph.mpo","mpgraph.mpy", - "mprun.mp", "mprun.mpd", "mprun.mpo", "mprun.mpy", - "xlscript.xsl") ; -my @forsuresuffixes = - ("tui","tup","ted","tes","top", - "log","tmp","run","bck","rlg", - "mpt","mpx","mpd","mpo") ; -my @texonlysuffixes = - ("dvi","ps","pdf") ; -my @texnonesuffixes = - ("tuo","tub","top") ; - -if ($PurgeAllFiles) - { push @forsuresuffixes, @texnonesuffixes ; @texnonesuffixes = [] } - -sub PurgeFiles # no my in foreach - { my $pattern = $ARGV[0] ; - my $strippedname ; - my $basename ; - my @files = () ; - if ($pattern eq '') - { $pattern = "*.*" ; - @files = glob $pattern } - else - { $pattern = $ARGV[0] . "-*.*" ; - @files = glob $pattern ; - $pattern = $ARGV[0] . ".*" ; - push(@files,glob $pattern) } - @files = sort @files ; - print " purging files : $pattern\n\n" ; - foreach $file (@dontaskprefixes) - { if (-e $file) - { RemoveContextFile($file) } } - foreach $file (@dontasksuffixes) - { if (-e $file) - { RemoveContextFile($file) } } - foreach $suffix (@dontasksuffixes) - { foreach (@files) - { if (/$suffix$/i) - { RemoveContextFile($_) } } } - foreach $suffix (@forsuresuffixes) - { foreach (@files) - { if (/\.$suffix$/i) - { RemoveContextFile($_) } } } - foreach $file (@files) - { if ($file =~ /(.*?)\.\d+$/) - { $basename = $1 ; - if (($file =~ /mp(graph|run)/) || (-e "$basename.mp")) - { RemoveContextFile($file) } } } - foreach $suffix (@texnonesuffixes) - { foreach (@files) - { if (/(.*)\.$suffix$/i) - { if ((-e "$1.tex")||(-e "$1.xml")||(-e "$1.fo")) - { KeepContextFile($_) } - else - { $strippedname = $1 ; - $strippedname =~ s/\-[a-z]$//io ; - if ((-e "$strippedname.tex")||(-e "$strippedname.xml")) - { KeepContextFile($_." (potential result file)") } - else - { RemoveContextFile($_) } } } } } - if ($removedfiles||$keptfiles||$persistentfiles) - { print "\n" } - print " removed files : $removedfiles\n" ; - print " kept files : $keptfiles\n" ; - print " persistent files : $persistentfiles\n" ; - print " reclaimed bytes : $reclaimedbytes\n" } - -#D Another undocumented feature. -# -# obsolete, i.e now in pdftools, so this will become: -# -# sub AnalyzeFile -# { system("pdftools --analyze $ARGV[0]") } - -sub AnalyzeFile - { my $filename = $ARGV[0] ; - return unless (($filename =~ /\.pdf/)&&(-e $filename)) ; - my $filesize = -s $filename ; - print " analyzing file : $filename\n" ; - print " file size : $filesize\n" ; - open (PDF, $filename) ; - binmode PDF ; - my $Object = 0 ; - my $Annot = 0 ; - my $Link = 0 ; - my $Widget = 0 ; - my $Named = 0 ; - my $Script = 0 ; - my $Cross = 0 ; - while (<PDF>) - { while (/\d+\s+\d+\s+obj/go) { ++$Object } ; - while (/\/Type\s*\/Annot/go) { ++$Annot } ; - while (/\/GoToR\s*\/F/go) { ++$Cross } ; - while (/\/Subtype\s*\/Link/go) { ++$Link } ; - while (/\/Subtype\s*\/Widget/go) { ++$Widget } ; - while (/\/S\s*\/Named/go) { ++$Named } ; - while (/\/S\s*\/JavaScript/go) { ++$Script } } - close (PDF) ; - print " objects : $Object\n" ; - print " annotations : $Annot\n" ; - print " links : $Link ($Named named / $Script scripts / $Cross files)\n" ; - print " widgets : $Widget\n" } - -# moved to ctxtools -# -# sub FilterPages -# { system("ctxtools $ARGV{0]") } - -sub FilterPages # temp feature / no reporting - { my $filename = $ARGV[0] ; - return unless -f "$filename.pdf" ; - my $old = '' ; - my $n = 0 ; - if (open(PDF,"<$filename.pdf") && open(TUO,">>$filename.tuo")) - { binmode PDF ; - while (<PDF>) - { chomp ; - if (($_ eq '/Type /Page') && ($old =~ /^(\d+)\s+0\s+obj/o)) - { ++$n ; $p = $1 ; - print TUO "\\objectreference{PDFP}{$n}{$p}{$n}\n" } - else - { $old = $_ } } - close(PDF) ; - close(TUO) } } - - ShowBanner ; - -if ($UnknownOptions ) { ShowHelpInfo } # not yet done -elsif ($ProcessReferences) { HandleReferences } -elsif ($ProcessDocuments ) { HandleDocuments } -elsif ($ProcessSources ) { HandleSources } -elsif ($ProcessSetups ) { HandleSetups } -elsif ($ProcessTemplates ) { HandleEditorCues } -elsif ($ProcessInfos ) { HandleEditorCues } -elsif ($ProcessFigures ) { HandleFigures } -elsif ($ProcessLogFile ) { HandleLogFile } -elsif ($PurgeFiles ) { PurgeFiles } -elsif ($PurgeAllFiles ) { PurgeFiles } -elsif ($AnalyzeFile ) { AnalyzeFile } -elsif ($FilterPages ) { FilterPages } -elsif ($ProcessHelp ) { ShowHelpInfo } # redundant -else { ShowHelpInfo } - -print "\n" ; -print " remark : 'texutil' is now part of 'texexec'\n" ; -print " warning : use 'texmfstart texutil' instead\n" ; - -#D So far. diff --git a/scripts/context/perl/utiplug.pm b/scripts/context/perl/utiplug.pm deleted file mode 100644 index 2bc162e1e..000000000 --- a/scripts/context/perl/utiplug.pm +++ /dev/null @@ -1,30 +0,0 @@ -package utiplug ; - -my @data ; -my @result ; - -sub utiplug::initialize - { @data = () } - -sub utiplug::process - { @data = sort @data ; - for (my $i=0; $i<@data; $i++) - { @result[$i] = "\\plugintest\{$i\}\{$data[$i]\}" } } - -sub utiplug::handle - { my ($self,$text,$rest) = @_ ; push @data, $text } - -sub utiplug::identify - { return "utiplug test plugin" } - -sub utiplug::report - { my $keys = @data ; - if ($keys) - { return ("done", "keys:$keys") } - else - { return ("nothing done") } } - -sub utiplug::results - { return @result } - -1 ; diff --git a/scripts/context/ruby/base/tex.rb b/scripts/context/ruby/base/tex.rb index 582ff640c..55d62c8ac 100644 --- a/scripts/context/ruby/base/tex.rb +++ b/scripts/context/ruby/base/tex.rb @@ -112,8 +112,8 @@ class TEX ['tex','standard'] .each do |b| @@mappaths[b] = 'dvips' end ['pdftex','pdfetex'] .each do |b| @@mappaths[b] = 'pdftex' end - ['aleph','omega','xetex','petex'] .each do |b| @@mappaths[b] = 'dvipdfm' end - ['dvipdfm', 'dvipdfmx', 'xdvipdfmx'] .each do |b| @@mappaths[b] = 'dvipdfm' end + ['aleph','omega','xetex','petex'] .each do |b| @@mappaths[b] = 'dvipdfmx' end + ['dvipdfm', 'dvipdfmx', 'xdvipdfmx'] .each do |b| @@mappaths[b] = 'dvipdfmx' end ['xdv','xdv2pdf'] .each do |b| @@mappaths[b] = 'dvips' end # todo norwegian (no) @@ -124,9 +124,9 @@ class TEX ['cont-de','de','german'] .each do |f| @@texformats[f] = 'cont-de' end ['cont-it','it','italian'] .each do |f| @@texformats[f] = 'cont-it' end ['cont-fr','fr','french'] .each do |f| @@texformats[f] = 'cont-fr' end - ['cont-cz','cz','czech'] .each do |f| @@texformats[f] = 'cont-cz' end + ['cont-cs','cs','cont-cz','cz','czech'] .each do |f| @@texformats[f] = 'cont-cs' end ['cont-ro','ro','romanian'] .each do |f| @@texformats[f] = 'cont-ro' end - ['cont-uk','uk','british'] .each do |f| @@texformats[f] = 'cont-uk' end + ['cont-gb','gb','cont-uk','uk','british'] .each do |f| @@texformats[f] = 'cont-gb' end ['mptopdf'] .each do |f| @@texformats[f] = 'mptopdf' end ['latex'] .each do |f| @@texformats[f] = 'latex.ltx' end @@ -141,7 +141,7 @@ class TEX ['plain','default','standard','mptopdf'] .each do |f| @@texmethods[f] = 'plain' end ['cont-en','cont-nl','cont-de','cont-it', - 'cont-fr','cont-cz','cont-ro','cont-uk'] .each do |f| @@texmethods[f] = 'context' end + 'cont-fr','cont-cs','cont-ro','cont-gb'] .each do |f| @@texmethods[f] = 'context' end ['latex','pdflatex'] .each do |f| @@texmethods[f] = 'latex' end ['plain','default','standard'] .each do |f| @@mpsmethods[f] = 'plain' end @@ -151,7 +151,7 @@ class TEX @@mpsmakestr['plain'] = @@platformslash + "dump" ['cont-en','cont-nl','cont-de','cont-it', - 'cont-fr','cont-cz','cont-ro','cont-uk'] .each do |f| @@texprocstr[f] = @@platformslash + "emergencyend" end + 'cont-fr','cont-cs','cont-ro','cont-gb'] .each do |f| @@texprocstr[f] = @@platformslash + "emergencyend" end @@runoptions['aleph'] = ['--8bit'] @@runoptions['luatex'] = ['--file-line-error'] @@ -640,10 +640,14 @@ class TEX report("using tex format path #{texformatpath}") Dir.chdir(texformatpath) rescue false if FileTest.writable?(texformatpath) then - if texformats.length > 0 then - makeuserfile - makeresponsefile - end + # from now on we no longer support this; we load + # all patterns and if someone wants another + # interface language ... cook up a fmt or usr file + # + # if texformats.length > 0 then + # makeuserfile + # makeresponsefile + # end if texengine == 'luatex' then cleanupluafiles texformats.each do |texformat| @@ -2174,30 +2178,57 @@ end end def checkmpgraphics(mpname) + # in practice the checksums will differ because of multiple instances + # ok, we could save the mpy/mpo files by number, but not now mpoptions = '' if getvariable('makempy') then mpoptions += " --makempy " end + mponame = File.suffixed(mpname,'mpo') + mpyname = File.suffixed(mpname,'mpy') + pdfname = File.suffixed(mpname,'pdf') + tmpname = File.suffixed(mpname,'tmp') if getvariable('mpyforce') || getvariable('forcempy') then mpoptions += " --force " else - mponame = File.suffixed(mpname,'mpo') - mpyname = File.suffixed(mpname,'mpy') return false unless File.atleast?(mponame,32) mpochecksum = FileState.new.checksum(mponame) return false if mpochecksum.empty? # where does the checksum get into the file? # maybe let texexec do it? # solution: add one if not present or update when different - if f = File.silentopen(mpyname) then - str = f.gets.chomp - f.close - if str =~ /^\%\s*mpochecksum\s*\:\s*(\d+)/o then - return false if mpochecksum == $1 + begin + mpydata = IO.read(mpyname) + if mpydata then + if mpydata =~ /^\%\s*mpochecksum\s*\:\s*([A-Z0-9]+)$/mo then + checksum = $1 + if mpochecksum == checksum then + return false + end + end + end + rescue + # no file + end + end + # return Kpse.runscript('makempy',mpname) + # only pdftex + flags = ['--noctx','--process','--batch','--once'] + result = runtexexec([mponame], flags, 1) + runcommand(["pstoedit","-ssp -dt -f mpost", pdfname,tmpname]) + tmpdata = IO.read(tmpname) + if tmpdata then + if mpy = openedfile(mpyname) then + mpy << "% mpochecksum: #{mpochecksum}\n" + tmpdata.scan(/beginfig(.*?)endfig/mo) do |s| + mpy << "begingraphictextfig#{s}endgraphictextfig\n" end + mpy.close() end end - return Kpse.runscript('makempy',mpname) + File.silentdelete(tmpname) + File.silentdelete(pdfname) + return true end def checkmplabels(mpname) diff --git a/scripts/context/ruby/ctxtools.rb b/scripts/context/ruby/ctxtools.rb index 00d2b494b..70c9ce243 100644 --- a/scripts/context/ruby/ctxtools.rb +++ b/scripts/context/ruby/ctxtools.rb @@ -222,7 +222,7 @@ class Commands interfaces = @commandline.arguments if interfaces.empty? then - interfaces = ['en','cz','de','it','nl','ro','fr'] + interfaces = ['en','cs','de','it','nl','ro','fr'] end interfaces.each do |interface| @@ -320,7 +320,7 @@ class Commands interfaces = @commandline.arguments if interfaces.empty? then - interfaces = ['cz','de','it','nl','ro','fr'] + interfaces = ['cs','de','it','nl','ro','fr'] else interfaces.delete('en') end @@ -1219,14 +1219,15 @@ class Language def located(filename) begin - fname = Kpse.found(filename, 'context') - if FileTest.file?(fname) then - report("using file #{fname}") - return fname - else - report("file #{filename} is not present") - return nil + ["context","plain","latex"].each do |name| # fallbacks needed for czech patterns + fname = Kpse.found(filename, name) + if FileTest.file?(fname) then + report("using file #{fname}") + return fname + end end + report("file #{filename} is not present") + return nil rescue report("file #{filename} cannot be located using kpsewhich") return nil @@ -1311,9 +1312,9 @@ class Language remap(/\"o/, "[odiaeresis]") remap(/\"u/, "[udiaeresis]") when 'fr' then - demap(/\\n\{/, "\\keep{") - remap(/\\ae/, "[adiaeresis]") - remap(/\\oe/, "[odiaeresis]") + demap(/\\n\{/, "\\delete{") + remap(/\\ae/, "[aeligature]") + remap(/\\oe/, "[oeligature]") when 'la' then # \lccode`'=`' somewhere else, todo demap(/\\c\{/, "\\delete{") @@ -1324,7 +1325,7 @@ class Language remap("a2|", "[greekalphaiotasub]") remap("h2|", "[greeketaiotasub]") remap("w2|", "[greekomegaiotasub]") - remap(">2r1<2r", "[2ῤ1ῥ]") + remap(">2r1<2r", "[2ῤ1ῥ]") remap(">a2n1wdu'", "[ἀ2ν1ωδύ]") remap(">e3s2ou'", "[ἐ3σ2ού]") # main conversion @@ -1561,6 +1562,8 @@ class Language remap(/\xC0/, "[cyrillicyu]") remap(/\xD1/, "[cyrillicya]") remap(/\xA3/, "[cyrillicyo]") + when 'tr' then + remap(/\^\^11/, "[dotlessi]") else end @@ -1632,7 +1635,7 @@ class Commands @@languagedata['ba' ] = [ 'ec' , ['bahyph.tex'] ] @@languagedata['ca' ] = [ 'ec' , ['cahyph.tex'] ] @@languagedata['cy' ] = [ 'ec' , ['cyhyph.tex'] ] - @@languagedata['cz' ] = [ 'ec' , ['czhyphen.tex','czhyphen.ex'] ] + @@languagedata['cs' ] = [ 'ec' , ['czhyphen.tex','czhyphen.ex'] ] @@languagedata['de' ] = [ 'ec' , ['dehyphn.tex'] ] @@languagedata['deo'] = [ 'ec' , ['dehypht.tex'] ] @@languagedata['da' ] = [ 'ec' , ['dkspecial.tex','dkcommon.tex'] ] @@ -1644,7 +1647,7 @@ class Commands # ghyphen.readme ghyph31.readme grphyph @@languagedata['hr' ] = [ 'ec' , ['hrhyph.tex'] ] @@languagedata['hu' ] = [ 'ec' , ['huhyphn.tex'] ] - @@languagedata['en' ] = [ 'default' , [['ushyphmax.tex'],['ushyph.tex'],['hyphen.tex']] ] + @@languagedata['us' ] = [ 'default' , [['ushyphmax.tex'],['ushyph.tex'],['hyphen.tex']] ] @@languagedata['us' ] = [ 'default' , [['ushyphmax.tex'],['ushyph.tex'],['hyphen.tex']] ] # inhyph.tex @@languagedata['is' ] = [ 'ec' , ['ishyph.tex'] ] @@ -1664,7 +1667,7 @@ class Commands # srhyphc.tex / cyrillic @@languagedata['sv' ] = [ 'ec' , ['svhyph.tex'] ] @@languagedata['tr' ] = [ 'ec' , ['tkhyph.tex'] ] - @@languagedata['uk' ] = [ 'default' , [['ukhyphen.tex'],['ukhyph.tex']] ] + @@languagedata['gb' ] = [ 'default' , [['ukhyphen.tex'],['ukhyph.tex']] ] # @@languagedata['ru' ] = [ 't2a' , ['ruhyphal.tex'] ] # t2a does not work @@languagedata['ru' ] = [ 'cyr' , ['ruhyphal.tex'] ] end diff --git a/scripts/context/ruby/texmfstart.rb b/scripts/context/ruby/texmfstart.rb index e43929213..42a26a09c 100644 --- a/scripts/context/ruby/texmfstart.rb +++ b/scripts/context/ruby/texmfstart.rb @@ -2115,6 +2115,12 @@ end def make(filename,windows=false,linux=false,remove=false) basename = File.basename(filename).gsub(/\.[^.]+?$/, '') +if @kpse.find_file(@tree,filename+".lua") or @kpse.find_file(@tree,filename+".rb") or @kpse.find_file(@tree,filename+".pl") then + # make stub indeed +else + report("no stub needed for '#{basename}'") + return +end if $stubpath == 'auto' then basename = File.dirname($0) + '/' + basename else @@ -2129,7 +2135,7 @@ def make(filename,windows=false,linux=false,remove=false) return elsif not remove then if windows then - ['bat','exe'].each do |suffix| + ['bat','cmd','exe'].each do |suffix| if FileTest.file?("#{basename}.#{suffix}") then report("windows stub '#{basename}.#{suffix}' skipped (already present)") return diff --git a/scripts/context/stubs/mswin/ctxtools.bat b/scripts/context/stubs/mswin/ctxtools.bat deleted file mode 100755 index f1f5e019e..000000000 --- a/scripts/context/stubs/mswin/ctxtools.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart ctxtools.rb %* diff --git a/scripts/context/stubs/mswin/exatools.bat b/scripts/context/stubs/mswin/exatools.bat deleted file mode 100755 index 57f798e82..000000000 --- a/scripts/context/stubs/mswin/exatools.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart exatools.rb %* diff --git a/scripts/context/stubs/mswin/makempy.bat b/scripts/context/stubs/mswin/makempy.bat deleted file mode 100755 index e339058c6..000000000 --- a/scripts/context/stubs/mswin/makempy.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart makempy.pl %* diff --git a/scripts/context/stubs/mswin/mpstools.bat b/scripts/context/stubs/mswin/mpstools.bat deleted file mode 100755 index df1732e17..000000000 --- a/scripts/context/stubs/mswin/mpstools.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart mpstools.rb %* diff --git a/scripts/context/stubs/mswin/mptopdf.bat b/scripts/context/stubs/mswin/mptopdf.bat deleted file mode 100755 index 242854337..000000000 --- a/scripts/context/stubs/mswin/mptopdf.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart mptopdf.pl %* diff --git a/scripts/context/stubs/mswin/pdftools.bat b/scripts/context/stubs/mswin/pdftools.bat deleted file mode 100755 index adc48eacf..000000000 --- a/scripts/context/stubs/mswin/pdftools.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart pdftools.rb %* diff --git a/scripts/context/stubs/mswin/pdftrimwhite.bat b/scripts/context/stubs/mswin/pdftrimwhite.bat deleted file mode 100755 index a7034b400..000000000 --- a/scripts/context/stubs/mswin/pdftrimwhite.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart pdftrimwhite.pl %* diff --git a/scripts/context/stubs/mswin/pstopdf.bat b/scripts/context/stubs/mswin/pstopdf.bat deleted file mode 100755 index 248e34caf..000000000 --- a/scripts/context/stubs/mswin/pstopdf.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart pstopdf.rb %* diff --git a/scripts/context/stubs/mswin/rlxtools.bat b/scripts/context/stubs/mswin/rlxtools.bat deleted file mode 100755 index b78dec13b..000000000 --- a/scripts/context/stubs/mswin/rlxtools.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart rlxtools.rb %* diff --git a/scripts/context/stubs/mswin/runtools.bat b/scripts/context/stubs/mswin/runtools.bat deleted file mode 100755 index 68a7b4f97..000000000 --- a/scripts/context/stubs/mswin/runtools.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart runtools.rb %* diff --git a/scripts/context/stubs/mswin/texexec.bat b/scripts/context/stubs/mswin/texexec.bat deleted file mode 100755 index 02b297b9c..000000000 --- a/scripts/context/stubs/mswin/texexec.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart texexec.rb %* diff --git a/scripts/context/stubs/mswin/texfind.bat b/scripts/context/stubs/mswin/texfind.bat deleted file mode 100755 index b7c11cbca..000000000 --- a/scripts/context/stubs/mswin/texfind.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart texfind %* diff --git a/scripts/context/stubs/mswin/texfont.bat b/scripts/context/stubs/mswin/texfont.bat deleted file mode 100755 index 3134bf14c..000000000 --- a/scripts/context/stubs/mswin/texfont.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart texfont.pl %* diff --git a/scripts/context/stubs/mswin/texshow.bat b/scripts/context/stubs/mswin/texshow.bat deleted file mode 100755 index 2060846ad..000000000 --- a/scripts/context/stubs/mswin/texshow.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart texshow.pl %* diff --git a/scripts/context/stubs/mswin/textools.bat b/scripts/context/stubs/mswin/textools.bat deleted file mode 100755 index 727b4a36d..000000000 --- a/scripts/context/stubs/mswin/textools.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart textools.rb %* diff --git a/scripts/context/stubs/mswin/texutil.bat b/scripts/context/stubs/mswin/texutil.bat deleted file mode 100755 index 1e63639bb..000000000 --- a/scripts/context/stubs/mswin/texutil.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart texutil.rb %* diff --git a/scripts/context/stubs/mswin/tmftools.bat b/scripts/context/stubs/mswin/tmftools.bat deleted file mode 100755 index c9c0c08bd..000000000 --- a/scripts/context/stubs/mswin/tmftools.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart tmftools.rb %* diff --git a/scripts/context/stubs/mswin/xmltools.bat b/scripts/context/stubs/mswin/xmltools.bat deleted file mode 100755 index 2de0e4457..000000000 --- a/scripts/context/stubs/mswin/xmltools.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -texmfstart xmltools.rb %* diff --git a/scripts/context/stubs/unix/context b/scripts/context/stubs/unix/context index c7341904f..fa62ba8d1 100755 --- a/scripts/context/stubs/unix/context +++ b/scripts/context/stubs/unix/context @@ -1,3 +1,2 @@ #!/bin/sh - mtxrun --script context "$@" diff --git a/scripts/context/stubs/unix/ctxtools b/scripts/context/stubs/unix/ctxtools deleted file mode 100755 index 84e47bbee..000000000 --- a/scripts/context/stubs/unix/ctxtools +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart ctxtools.rb "$@" diff --git a/scripts/context/stubs/unix/exatools b/scripts/context/stubs/unix/exatools deleted file mode 100755 index 50ff0f07e..000000000 --- a/scripts/context/stubs/unix/exatools +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart exatools.rb "$@" diff --git a/scripts/context/stubs/unix/makempy b/scripts/context/stubs/unix/makempy deleted file mode 100755 index 4bf7a1af2..000000000 --- a/scripts/context/stubs/unix/makempy +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart makempy.pl "$@" diff --git a/scripts/context/stubs/unix/mpstools b/scripts/context/stubs/unix/mpstools deleted file mode 100755 index b4c8f6345..000000000 --- a/scripts/context/stubs/unix/mpstools +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart mpstools.rb "$@" diff --git a/scripts/context/stubs/unix/mptopdf b/scripts/context/stubs/unix/mptopdf deleted file mode 100755 index 980a3123d..000000000 --- a/scripts/context/stubs/unix/mptopdf +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart mptopdf.pl "$@" diff --git a/scripts/context/stubs/unix/pdftools b/scripts/context/stubs/unix/pdftools deleted file mode 100755 index 92ee803a8..000000000 --- a/scripts/context/stubs/unix/pdftools +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart pdftools.rb "$@" diff --git a/scripts/context/stubs/unix/pdftrimwhite b/scripts/context/stubs/unix/pdftrimwhite deleted file mode 100755 index 00b5f525a..000000000 --- a/scripts/context/stubs/unix/pdftrimwhite +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart pdftrimwhite.pl "$@" diff --git a/scripts/context/stubs/unix/pstopdf b/scripts/context/stubs/unix/pstopdf deleted file mode 100755 index 5b38ed426..000000000 --- a/scripts/context/stubs/unix/pstopdf +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart pstopdf.rb "$@" diff --git a/scripts/context/stubs/unix/rlxtools b/scripts/context/stubs/unix/rlxtools deleted file mode 100755 index 41cea40fc..000000000 --- a/scripts/context/stubs/unix/rlxtools +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart rlxtools.rb "$@" diff --git a/scripts/context/stubs/unix/runtools b/scripts/context/stubs/unix/runtools deleted file mode 100755 index ff9a33379..000000000 --- a/scripts/context/stubs/unix/runtools +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart runtools.rb "$@" diff --git a/scripts/context/stubs/unix/texexec b/scripts/context/stubs/unix/texexec deleted file mode 100755 index 215817290..000000000 --- a/scripts/context/stubs/unix/texexec +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart texexec.rb "$@" diff --git a/scripts/context/stubs/unix/texfind b/scripts/context/stubs/unix/texfind deleted file mode 100755 index c054bdf52..000000000 --- a/scripts/context/stubs/unix/texfind +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart texfind "$@" diff --git a/scripts/context/stubs/unix/texfont b/scripts/context/stubs/unix/texfont deleted file mode 100755 index a91f786e3..000000000 --- a/scripts/context/stubs/unix/texfont +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart texfont.pl "$@" diff --git a/scripts/context/stubs/unix/texshow b/scripts/context/stubs/unix/texshow deleted file mode 100755 index afd62c339..000000000 --- a/scripts/context/stubs/unix/texshow +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart texshow.pl "$@" diff --git a/scripts/context/stubs/unix/textools b/scripts/context/stubs/unix/textools deleted file mode 100755 index 7445eac37..000000000 --- a/scripts/context/stubs/unix/textools +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart textools.rb "$@" diff --git a/scripts/context/stubs/unix/texutil b/scripts/context/stubs/unix/texutil deleted file mode 100755 index 607154af0..000000000 --- a/scripts/context/stubs/unix/texutil +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart texutil.rb "$@" diff --git a/scripts/context/stubs/unix/tmftools b/scripts/context/stubs/unix/tmftools deleted file mode 100755 index 7531a9663..000000000 --- a/scripts/context/stubs/unix/tmftools +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart tmftools.rb "$@" diff --git a/scripts/context/stubs/unix/xmltools b/scripts/context/stubs/unix/xmltools deleted file mode 100755 index 03086d043..000000000 --- a/scripts/context/stubs/unix/xmltools +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -texmfstart xmltools.rb "$@" |