summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2007-12-05 13:56:00 +0100
committerHans Hagen <pragma@wxs.nl>2007-12-05 13:56:00 +0100
commit6312e2b2913bc7de6f3c0ba30b993e2b4714edf1 (patch)
treee0e90382ddb930a0b4f534824892235b343dcdc4 /scripts
parent19af23ac5cb927d986a64ac1dc52ed2d7bad2450 (diff)
downloadcontext-6312e2b2913bc7de6f3c0ba30b993e2b4714edf1.tar.gz
stable 2007.12.05 13:56
Diffstat (limited to 'scripts')
-rw-r--r--scripts/context/lua/luatools.lua865
-rw-r--r--scripts/context/lua/mtx-babel.lua150
-rw-r--r--scripts/context/lua/mtx-cache.lua8
-rw-r--r--scripts/context/lua/mtx-chars.lua8
-rw-r--r--scripts/context/lua/mtx-context.lua27
-rw-r--r--scripts/context/lua/mtx-convert.lua86
-rw-r--r--scripts/context/lua/mtx-fonts.lua9
-rw-r--r--scripts/context/lua/mtx-watch.lua224
-rw-r--r--scripts/context/lua/mtxrun.lua1292
-rw-r--r--scripts/context/lua/scite-ctx.lua924
-rw-r--r--scripts/context/ruby/base/kpse.rb8
-rw-r--r--scripts/context/ruby/base/tex.rb29
-rw-r--r--scripts/context/ruby/base/texutil.rb4
-rw-r--r--scripts/context/ruby/graphics/gs.rb6
-rw-r--r--scripts/context/ruby/texexec.rb15
-rw-r--r--scripts/context/ruby/www/exa.rb1
-rw-r--r--scripts/context/ruby/www/lib.rb8
17 files changed, 2166 insertions, 1498 deletions
diff --git a/scripts/context/lua/luatools.lua b/scripts/context/lua/luatools.lua
index d53180cfa..1dc67519e 100644
--- a/scripts/context/lua/luatools.lua
+++ b/scripts/context/lua/luatools.lua
@@ -141,6 +141,10 @@ function string.piecewise(str, pat, fnc) -- variant of split
for k in string.splitter(str,pat) do fnc(k) end
end
+--~ function string.piecewise(str, pat, fnc) -- variant of split
+--~ for k in str:splitter(pat) do fnc(k) end
+--~ end
+
--~ do if lpeg then
--~ -- this alternative is 30% faster esp when we cache them
@@ -158,7 +162,7 @@ end
--~ split = lpeg.Ct(c*(p*c)^0)
--~ splitters[separator] = split
--~ end
---~ return lpeg.match(split,self)
+--~ return lpeg.match(split,self) -- split:match(self)
--~ else
--~ return { }
--~ end
@@ -315,7 +319,7 @@ end
--~ return self .. self.rep(chr or " ",n-#self)
--~ end
-function string:padd(n,chr)
+function string:rpadd(n,chr)
local m = n-#self
if m > 0 then
return self .. self.rep(chr or " ",m)
@@ -324,6 +328,17 @@ function string:padd(n,chr)
end
end
+function string:lpadd(n,chr)
+ local m = n-#self
+ if m > 0 then
+ return self.rep(chr or " ",m) .. self
+ else
+ return self
+ end
+end
+
+string.padd = string.rpadd
+
function is_number(str)
return str:find("^[%-%+]?[%d]-%.?[%d+]$") == 1
end
@@ -349,6 +364,49 @@ function string:split_settings() -- no {} handling, see l-aux for lpeg variant
end
+-- filename : l-lpeg.lua
+-- 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['l-lpeg'] = 1.001
+
+--~ l-lpeg.lua :
+
+--~ lpeg.digit = lpeg.R('09')^1
+--~ lpeg.sign = lpeg.S('+-')^1
+--~ lpeg.cardinal = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.integer = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.float = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
+--~ lpeg.number = lpeg.float + lpeg.integer
+--~ lpeg.oct = lpeg.P("0") * lpeg.R('07')^1
+--~ lpeg.hex = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
+--~ lpeg.uppercase = lpeg.P("AZ")
+--~ lpeg.lowercase = lpeg.P("az")
+
+--~ lpeg.eol = lpeg.S('\r\n\f')^1 -- includes formfeed
+--~ lpeg.space = lpeg.S(' ')^1
+--~ lpeg.nonspace = lpeg.P(1-lpeg.space)^1
+--~ lpeg.whitespace = lpeg.S(' \r\n\f\t')^1
+--~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
+
+function lpeg.anywhere(pattern) --slightly adapted from website
+ return lpeg.P { lpeg.P(pattern) + 1 * lpeg.V(1) }
+end
+
+function lpeg.startswith(pattern) --slightly adapted
+ return lpeg.P(pattern)
+end
+
+--~ g = lpeg.splitter(" ",function(s) ... end) -- gmatch:lpeg = 3:2
+
+function lpeg.splitter(pattern, action)
+ return (((1-lpeg.P(pattern))^1)/action+1)^0
+end
+
+
+
+
-- filename : l-table.lua
-- comment : split off from luat-lib
-- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
@@ -422,6 +480,7 @@ function table.merge(t, ...)
t[k] = v
end
end
+ return t
end
function table.merged(...)
@@ -434,6 +493,25 @@ function table.merged(...)
return tmp
end
+function table.imerge(t, ...)
+ for _, list in ipairs({...}) do
+ for k,v in ipairs(list) do
+ t[#t+1] = v
+ end
+ end
+ return t
+end
+
+function table.imerged(...)
+ local tmp = { }
+ for _, list in ipairs({...}) do
+ for _,v in pairs(list) do
+ tmp[#tmp+1] = v
+ end
+ end
+ return tmp
+end
+
if not table.fastcopy then
function table.fastcopy(old) -- fast one
@@ -441,11 +519,15 @@ if not table.fastcopy then
local new = { }
for k,v in pairs(old) do
if type(v) == "table" then
- new[k] = table.copy(v)
+ new[k] = table.fastcopy(v) -- was just table.copy
else
new[k] = v
end
end
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
return new
else
return { }
@@ -456,30 +538,32 @@ end
if not table.copy then
- function table.copy(t, _lookup_table) -- taken from lua wiki
- _lookup_table = _lookup_table or { }
+ function table.copy(t, tables) -- taken from lua wiki, slightly adapted
+ tables = tables or { }
local tcopy = {}
- if not _lookup_table[t] then
- _lookup_table[t] = tcopy
+ if not tables[t] then
+ tables[t] = tcopy
end
- for i,v in pairs(t) do
+ for i,v in pairs(t) do -- brrr, what happens with sparse indexed
if type(i) == "table" then
- if _lookup_table[i] then
- i = _lookup_table[i]
+ if tables[i] then
+ i = tables[i]
else
- i = table.copy(i, _lookup_table)
+ i = table.copy(i, tables)
end
end
if type(v) ~= "table" then
tcopy[i] = v
+ elseif tables[v] then
+ tcopy[i] = tables[v]
else
- if _lookup_table[v] then
- tcopy[i] = _lookup_table[v]
- else
- tcopy[i] = table.copy(v, _lookup_table)
- end
+ tcopy[i] = table.copy(v, tables)
end
end
+ local mt = getmetatable(t)
+ if mt then
+ setmetatable(tcopy,mt)
+ end
return tcopy
end
@@ -514,6 +598,8 @@ end
do
+ -- 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
@@ -873,6 +959,25 @@ function table.tohash(t)
return h
end
+function table.contains(t, v)
+ if t then
+ for i=1, #t do
+ if t[i] == v then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+function table.count(t)
+ local n, e = 0, next(t)
+ while e do
+ n, e = n + 1, next(t,e)
+ end
+ return n
+end
+
--~ function table.are_equal(a,b)
--~ return table.serialize(a) == table.serialize(b)
--~ end
@@ -1053,6 +1158,38 @@ do
end
+function io.ask(question,default,options)
+ while true do
+ io.write(question)
+ if options then
+ io.write(string.format(" [%s]",table.concat(options,"|")))
+ end
+ if default then
+ io.write(string.format(" [%s]",default))
+ end
+ io.write(string.format(" "))
+ local answer = io.read()
+ answer = answer:gsub("^%s*(.*)%s*$","%1")
+ if answer == "" and default then
+ return default
+ elseif not options then
+ return answer
+ else
+ for _,v in pairs(options) do
+ if v == answer then
+ return answer
+ end
+ end
+ local pattern = "^" .. answer
+ for _,v in pairs(options) do
+ if v:find(pattern) then
+ return v
+ end
+ end
+ end
+ end
+end
+
-- filename : l-number.lua
-- comment : split off from luat-lib
@@ -1064,6 +1201,31 @@ if not versions then versions = { } end versions['l-number'] = 1.001
if not number then number = { } end
+-- a,b,c,d,e,f = number.toset(100101)
+
+function number.toset(n)
+ return (tostring(n)):match("(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
+end
+
+-- the lpeg way is slower on 8 digits, but faster on 4 digits, some 7.5%
+-- on
+--
+-- for i=1,1000000 do
+-- local a,b,c,d,e,f,g,h = number.toset(12345678)
+-- local a,b,c,d = number.toset(1234)
+-- local a,b,c = number.toset(123)
+-- end
+--
+-- of course dedicated "(.)(.)(.)(.)" matches are even faster
+
+do
+ local one = lpeg.C(1-lpeg.S(''))^1
+
+ function number.toset(n)
+ return lpeg.match(one,tostring(n))
+ end
+end
+
-- filename : l-os.lua
@@ -1110,7 +1272,7 @@ if md5 then do
if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end
if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end
- if not md5.dec then function md5.dec(str) return convert(stt,"%03i") end end
+ if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end
end end
@@ -1138,7 +1300,7 @@ function file.addsuffix(filename, suffix)
end
function file.replacesuffix(filename, suffix)
- return filename:gsub("%.%a+$", "." .. suffix)
+ return (filename:gsub("%.%a+$", "." .. suffix))
end
function file.dirname(name)
@@ -1150,7 +1312,7 @@ function file.basename(name)
end
function file.extname(name)
- return name:match("^.+%.(.-)$") or ""
+ return name:match("^.+%.([^/\\]-)$") or ""
end
function file.join(...)
@@ -1252,15 +1414,18 @@ dir = { }
if lfs then
function dir.glob_pattern(path,patt,recurse,action)
- for name in lfs.dir(path) do
- local full = path .. '/' .. name
- local mode = lfs.attributes(full,'mode')
- if mode == 'file' then
- if name:find(patt) then
- action(full)
+ local ok, scanner = xpcall(function() return lfs.dir(path) end, function() end) -- kepler safe
+ if ok and type(scanner) == "function" then
+ for name in scanner do
+ local full = path .. '/' .. name
+ local mode = lfs.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
+ dir.glob_pattern(full,patt,recurse,action)
end
- elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
- dir.glob_pattern(full,patt,recurse,action)
end
end
end
@@ -1285,6 +1450,30 @@ if lfs then
return t
end
+ function dir.globfiles(path,recurse,func,files)
+ if type(func) == "string" then
+ local s = func -- alas, we need this indirect way
+ func = function(name) return name:find(s) end
+ end
+ files = files or { }
+ for name in lfs.dir(path) do
+ if name:find("^%.") then
+ --- skip
+ elseif lfs.attributes(name,'mode') == "directory" then
+ if recurse then
+ dir.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
+ end
+ end
+ return files
+ end
+
-- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
-- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
-- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
@@ -1346,11 +1535,21 @@ function boolean.tonumber(b)
if b then return 1 else return 0 end
end
-function toboolean(str)
- if type(str) == "string" then
- return str == "true" or str == "yes" or str == "on" or str == "1"
- elseif type(str) == "number" then
- return tonumber(str) ~= 0
+function toboolean(str,tolerant)
+ if tolerant then
+ if type(str) == "string" then
+ return str == "true" or str == "yes" or str == "on" or str == "1"
+ elseif type(str) == "number" then
+ return tonumber(str) ~= 0
+ elseif type(str) == "nil" then
+ return false
+ else
+ return str
+ end
+ elseif str == "true" then
+ return true
+ elseif str == "false" then
+ return false
else
return str
end
@@ -1641,10 +1840,15 @@ function utils.merger.selfclean(name)
)
end
+utils.lua.compile_strip = true
+
function utils.lua.compile(luafile, lucfile)
-- utils.report("compiling",luafile,"into",lucfile)
os.remove(lucfile)
- local command = "-s -o " .. string.quote(lucfile) .. " " .. string.quote(luafile)
+ local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile)
+ if utils.lua.compile_strip then
+ command = "-s " .. command
+ end
if os.execute("texluac " .. command) == 0 then
return true
elseif os.execute("luac " .. command) == 0 then
@@ -1742,6 +1946,10 @@ function environment.showarguments()
end
end
+function environment.setargument(name,value)
+ environment.arguments[name] = value
+end
+
function environment.argument(name)
if environment.arguments[name] then
return environment.arguments[name]
@@ -1823,6 +2031,7 @@ end
-- Beware, loading and saving is overloaded in luat-tmp!
-- todo: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller)
+-- todo: check escaping in find etc, too much, too slow
if not versions then versions = { } end versions['luat-inp'] = 1.001
if not environment then environment = { } end
@@ -2060,7 +2269,7 @@ input.settrace(tonumber(os.getenv("MTX.INPUT.TRACE") or os.getenv("MTX_INPUT_TRA
-- These functions can be used to test the performance, especially
-- loading the database files.
-function input.start_timing(instance)
+function input.starttiming(instance)
if instance then
instance.starttime = os.clock()
if not instance.loadtime then
@@ -2069,7 +2278,7 @@ function input.start_timing(instance)
end
end
-function input.stop_timing(instance, report)
+function input.stoptiming(instance, report)
if instance and instance.starttime then
instance.stoptime = os.clock()
local loadtime = instance.stoptime - instance.starttime
@@ -2083,9 +2292,6 @@ function input.stop_timing(instance, report)
end
end
-input.stoptiming = input.stop_timing
-input.starttiming = input.start_timing
-
function input.elapsedtime(instance)
return string.format("%0.3f",instance.loadtime or 0)
end
@@ -2398,99 +2604,106 @@ function input.generatedatabase(instance,specification)
return input.methodhandler('generators', instance, specification)
end
-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 .. '/'
- else
- full = spec
- end
- for name in directory(full) do
- if name:find("^%.") then
- -- skip
- elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%|%<%>%,%?\n\r\t]") then
- -- texio.write_nl("skipping " .. name)
- -- skip
+do
+
+ 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 .. '/'
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
+ 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
- else
- files[name] = path
- local lower = name:lower()
- if name ~= lower then
- files["remap:"..lower] = name
- r = r + 1
+ 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
end
end
end
end
- end
- action()
- input.report(string.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
- if not small then
- if type(fl) == 'string' then
- files[line] = { fl, path } -- table
- else
- fl[#fl+1] = path
+ action()
+ input.report(string.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
+ if not small then
+ if type(fl) == 'string' then
+ files[line] = { fl, path } -- table
+ else
+ fl[#fl+1] = path
+ end
+ end
+ else
+ files[line] = path -- string
+ local lower = line:lower()
+ if line ~= lower then
+ files["remap:"..lower] = line
end
end
else
- files[line] = path -- string
- local lower = line:lower()
- if line ~= lower then
- files["remap:"..lower] = line
- end
+ path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line
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
@@ -2790,7 +3003,7 @@ end
function input.list_configurations(instance)
for _,key in pairs(table.sortedkeys(instance.kpsevars)) do
- if not instance.pattern or instance.pattern == "" or key:find(instance.pattern) then
+ if not instance.pattern or (instance.pattern=="") or key:find(instance.pattern) then
print(key.."\n")
for i,c in ipairs(instance.order) do
local str = c[key]
@@ -2913,10 +3126,168 @@ end
-- a,b,c/{p,q,r}/d/{x,y,z}//
-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a{b,c}{d,e}f
+-- {a,b,c,d}
+-- {a,b,c/{p,q,r},d}
+-- {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}}
+
+-- 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
+-- fuzzy concatenating we can probably gain a bit with selectively
+-- applying lpeg, but experiments with lpeg parsing this proved not to
+-- work that well; the parsing is ok, but dealing with the resulting
+-- table is a pain because we need to work inside-out recursively
+
+--~ 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 { }
+--~ while true do
+--~ local done = false
+--~ while true do
+--~ ok = false
+--~ str = str:gsub("([^{},]+){([^{}]-)}", function(a,b)
+--~ local t = { }
+--~ for s in b:gmatch("([^,]+)") do
+--~ t[#t+1] = a .. s
+--~ end
+--~ ok, done = true, true
+--~ return "{" .. table.concat(t,",") .. "}"
+--~ end)
+--~ if not ok then break end
+--~ end
+--~ while true do
+--~ ok = false
+--~ str = str:gsub("{([^{}]-)}([^{},]+)", function(a,b)
+--~ local t = { }
+--~ for s in a:gmatch("([^,]+)") do
+--~ t[#t+1] = s .. b
+--~ end
+--~ ok, done = true, true
+--~ return "{" .. table.concat(t,",") .. "}"
+--~ end)
+--~ if not ok then break end
+--~ end
+--~ while true do
+--~ ok = false
+--~ str = str:gsub("([,{]){([^{}]+)}([,}])", function(a,b,c)
+--~ ok, done = true, true
+--~ return a .. b .. c
+--~ end)
+--~ if not ok then break end
+--~ end
+--~ if not done then break end
+--~ end
+--~ while true do
+--~ ok = false
+--~ 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 = true
+--~ return "{" .. table.concat(t,",") .. "}"
+--~ end)
+--~ if not ok then break end
+--~ end
+--~ while true do
+--~ ok = false
+--~ str = str:gsub("{([^{}]-)}", function(a)
+--~ ok = true
+--~ return a
+--~ end)
+--~ if not ok then break end
+--~ end
+--~ if validate then
+--~ for s in str:gmatch("([^,]+)") do
+--~ s = validate(s)
+--~ if s then t[#t+1] = s end
+--~ end
+--~ else
+--~ for s in str:gmatch("([^,]+)") do
+--~ t[#t+1] = s
+--~ end
+--~ end
+--~ return t
+--~ end
+
+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
+ while true do
+ local done = false
+ while true do
+ ok = false
+ str = str:gsub("([^{},]+){([^{}]-)}", function(a,b)
+ local t = { }
+ b:piecewise(",", function(s) t[#t+1] = a .. s end)
+ ok, done = true, true
+ return "{" .. concat(t,",") .. "}"
+ end)
+ if not ok then break end
+ end
+ while true do
+ ok = false
+ str = str:gsub("{([^{}]-)}([^{},]+)", function(a,b)
+ local t = { }
+ a:piecewise(",", function(s) t[#t+1] = s .. b end)
+ ok, done = true, true
+ return "{" .. concat(t,",") .. "}"
+ end)
+ if not ok then break end
+ end
+ while true do
+ ok = false
+ str = str:gsub("([,{]){([^{}]+)}([,}])", function(a,b,c)
+ ok, done = true, true
+ return a .. b .. c
+ end)
+ if not ok then break end
+ end
+ if not done then break end
+ end
+ while true do
+ 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
+ ok = false
+ str = str:gsub("{([^{}]-)}", function(a)
+ ok = true
+ return a
+ end)
+ if not ok then break end
+ end
+ if validate then
+ str:piecewise(",", function(s)
+ s = validate(s)
+ if s then t[#t+1] = s end
+ end)
+ else
+ str:piecewise(",", function(s)
+ t[#t+1] = s
+ end)
+ end
+ return t
+end
function input.aux.expanded_path(instance,pathlist)
-- a previous version fed back into pathlist
- local i, n, oldlist, newlist, ok = 0, 0, { }, { }, false
+ local newlist, ok = { }, false
for _,v in ipairs(pathlist) do
if v:find("[{}]") then
ok = true
@@ -2924,45 +3295,11 @@ function input.aux.expanded_path(instance,pathlist)
end
end
if ok then
- for _,v in ipairs(pathlist) do
- oldlist[#oldlist+1] = (v:gsub("([\{\}])", function(p)
- if p == "{" then
- i = i + 1
- if i > n then n = i end
- return "<" .. (i-1) .. ">"
- else
- i = i - 1
- return "</" .. i .. ">"
- end
- end))
- end
- for i=1,n do
- while true do
- local more = false
- local pattern = "^(.-)<"..(n-i)..">(.-)</"..(n-i)..">(.-)$"
- local t = { }
- for _,v in ipairs(oldlist) do
- local pre, mid, post = v:match(pattern)
- if pre and mid and post then
- more = true
- for vv in string.gmatch(mid..',',"(.-),") do
- if vv == '.' then
- t[#t+1] = pre..post
- else
- t[#t+1] = pre..vv..post
- end
- end
- else
- t[#t+1] = v
- end
- end
- oldlist = t
- if not more then break end
- end
- end
- for _,v in ipairs(oldlist) do
- v = file.collapse_path(v)
- if v ~= "" and not v:find(instance.dummy_path_expr) then newlist[#newlist+1] = v end
+ for _, v in ipairs(pathlist) do
+ input.aux.splitpathexpr(v, newlist, function(s)
+ s = file.collapse_path(s)
+ return s ~= "" and not s:find(instance.dummy_path_expr) and s
+ end)
end
else
for _,v in ipairs(pathlist) do
@@ -2975,6 +3312,83 @@ function input.aux.expanded_path(instance,pathlist)
return newlist
end
+--~ old one, imperfect and not that efficient
+--~
+--~ function input.aux.expanded_path(instance,pathlist)
+--~ -- a previous version fed back into pathlist
+--~ local i, n, oldlist, newlist, ok = 0, 0, { }, { }, false
+--~ for _,v in ipairs(pathlist) do
+--~ if v:find("[{}]") then
+--~ ok = true
+--~ break
+--~ end
+--~ end
+--~ if ok then
+--~ for _,v in ipairs(pathlist) do
+--~ oldlist[#oldlist+1] = (v:gsub("([\{\}])", function(p)
+--~ if p == "{" then
+--~ i = i + 1
+--~ if i > n then n = i end
+--~ return "<" .. (i-1) .. ">"
+--~ else
+--~ i = i - 1
+--~ return "</" .. i .. ">"
+--~ end
+--~ end))
+--~ end
+--~ for i=1,n do
+--~ while true do
+--~ local more = false
+--~ local pattern = "^(.-)<"..(n-i)..">(.-)</"..(n-i)..">(.-)$"
+--~ local t = { }
+--~ for _,v in ipairs(oldlist) do
+--~ local pre, mid, post = v:match(pattern)
+--~ if pre and mid and post then
+--~ more = true
+--~ for vv in string.gmatch(mid..',',"(.-),") do -- (mid, "([^,]+)")
+--~ if vv == '.' then
+--~ t[#t+1] = pre..post
+--~ else
+--~ t[#t+1] = pre..vv..post
+--~ end
+--~ end
+--~ else
+--~ t[#t+1] = v
+--~ end
+--~ end
+--~ oldlist = t
+--~ if not more then break end
+--~ end
+--~ end
+--~ if true then
+--~ -- many dups are possible due to messy resolve / order can be messed up too, brr !
+--~ local ok = { }
+--~ for _,o in ipairs(oldlist) do
+--~ for v in o:gmatch("([^,]+)") do
+--~ if not ok[v] then
+--~ ok[v] = true
+--~ v = file.collapse_path(v)
+--~ if v ~= "" and not v:find(instance.dummy_path_expr) then newlist[#newlist+1] = v end
+--~ end
+--~ end
+--~ end
+--~ else
+--~ for _,v in ipairs(oldlist) do
+--~ v = file.collapse_path(v)
+--~ if v ~= "" and not v:find(instance.dummy_path_expr) then newlist[#newlist+1] = v end
+--~ end
+--~ end
+--~ else
+--~ for _,v in ipairs(pathlist) do
+--~ for vv in string.gmatch(v..',',"(.-),") do
+--~ vv = file.collapse_path(v)
+--~ if vv ~= "" then newlist[#newlist+1] = vv end
+--~ end
+--~ end
+--~ end
+--~ return newlist
+--~ end
+
--~ function input.is_readable(name) -- brrr, get rid of this
--~ return name:find("^zip##") or file.is_readable(name)
--~ end
@@ -3073,24 +3487,51 @@ function input.suffixes_of_format(str)
end
end
-function input.aux.qualified_path(filename) -- make platform dependent / not good yet
- return
- filename:find("^%.+/") or
- filename:find("^/") or
- filename:find("^%a+%:") or
- filename:find("^%a+##")
-end
+--~ function input.aux.qualified_path(filename) -- make platform dependent / not good yet
+--~ return
+--~ filename:find("^%.+/") or
+--~ filename:find("^/") or
+--~ filename:find("^%a+%:") or
+--~ filename:find("^%a+##")
+--~ end
+
+--~ function input.normalize_name(original)
+--~ -- internally we use type##spec##subspec ; this hackery slightly slows down searching
+--~ local str = original or ""
+--~ str = str:gsub("::", "##") -- :: -> ##
+--~ str = str:gsub("^(%a+)://" ,"%1##") -- zip:// -> zip##
+--~ str = str:gsub("(.+)##(.+)##/(.+)","%1##%2##%3") -- ##/spec -> ##spec
+--~ if (input.trace>1) and (original ~= str) then
+--~ input.logger('= normalizer',original.." -> "..str)
+--~ end
+--~ return str
+--~ end
-function input.normalize_name(original)
- -- internally we use type##spec##subspec ; this hackery slightly slows down searching
- local str = original or ""
- str = str:gsub("::", "##") -- :: -> ##
- str = str:gsub("^(%a+)://" ,"%1##") -- zip:// -> zip##
- str = str:gsub("(.+)##(.+)##/(.+)","%1##%2##%3") -- ##/spec -> ##spec
- if (input.trace>1) and (original ~= str) then
- input.logger('= normalizer',original.." -> "..str)
+do -- called about 700 times for an empty doc (font initializations etc)
+ -- i need to weed the font files for redundant calls
+
+ local letter = lpeg.R("az","AZ")
+ local separator = lpeg.P("##")
+
+ local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator
+ local normalized = lpeg.Cs(
+ (letter^1*(lpeg.P("://")/"##") * (1-lpeg.P(false))^1) +
+ (lpeg.P("::")/"##" + (1-separator)^1*separator*(1-separator)^1*separator*(lpeg.P("/")/"") + 1)^0
+ )
+
+ -- ./name ../name /name c: zip## (todo: use url internally and get rid of ##)
+ function input.aux.qualified_path(filename)
+ return qualified:match(filename)
+ end
+
+ -- zip:// -> zip## ; :: -> ## ; aa##bb##/cc -> aa##bb##cc
+ function input.normalize_name(original)
+ local str = normalized:match(original or "")
+ if input.trace > 1 and original ~= str then
+ input.logger('= normalizer',original.." -> "..str)
+ end
+ return str
end
- return str
end
-- split the next one up, better for jit
@@ -3455,13 +3896,13 @@ function input.automount(instance)
end
function input.load(instance)
- input.start_timing(instance)
+ input.starttiming(instance)
input.identify_cnf(instance)
input.load_cnf(instance)
input.expand_variables(instance)
input.load_hash(instance)
input.automount(instance)
- input.stop_timing(instance)
+ input.stoptiming(instance)
end
function input.for_files(instance, command, files, filetype, mustexist)
@@ -3755,7 +4196,7 @@ being written at the same time is small. We also need to extend
luatools with a recache feature.</p>
--ldx]]--
-caches = caches or { }
+caches = caches or { }
dir = dir or { }
texmf = texmf or { }
@@ -3768,8 +4209,18 @@ caches.tree = false
caches.temp = caches.temp or os.getenv("TEXMFCACHE") or os.getenv("HOME") or os.getenv("HOMEPATH") or os.getenv("VARTEXMF") or os.getenv("TEXMFVAR") or os.getenv("TMP") or os.getenv("TEMP") or os.getenv("TMPDIR") or nil
caches.paths = caches.paths or { caches.temp }
+input.usecache = not toboolean(os.getenv("TEXMFSHARECACHE") or "false",true) -- true
+
+if caches.temp and caches.temp ~= "" and lfs.attributes(caches.temp,"mode") ~= "directory" then
+ if io.ask(string.format("Should I create the cache path %s?",caches.temp), "no", { "yes", "no" }) == "yes" then
+ lfs.mkdir(caches.temp)
+ end
+end
if not caches.temp or caches.temp == "" then
- print("\nFATAL ERROR: NO VALID TEMPORARY PATH\n")
+ print("\nfatal error: there is no valid cache path defined\n")
+ os.exit()
+elseif lfs.attributes(caches.temp,"mode") ~= "directory" then
+ print(string.format("\nfatal error: cache path %s is not a directory\n",caches.temp))
os.exit()
end
@@ -3909,8 +4360,8 @@ do -- local report
function containers.is_valid(container, name)
if name and name ~= "" then
- local cs = container.storage[name]
- return cs and not table.is_empty(cs) and cs.cache_version == container.version
+ local storage = container.storage[name]
+ return storage and not table.is_empty(storage) and storage.cache_version == container.version
else
return false
end
@@ -3956,8 +4407,6 @@ end
-- since we want to use the cache instead of the tree, we will now
-- reimplement the saver.
-input.usecache = true
-
function input.aux.save_data(instance, dataname, check)
for cachename, files in pairs(instance[dataname]) do
local name
@@ -4357,7 +4806,7 @@ else
function input.registerzipfile(instance,zipname,tag)
if not zip.registeredfiles[zipname] then
- input.start_timing(instance)
+ input.starttiming(instance)
local z = zip.open(zipname)
if not z then
zipname = input.find_file(instance,zipname)
@@ -4370,7 +4819,7 @@ else
else
input.logger("? zipfile","unknown "..zipname)
end
- input.stop_timing(instance)
+ input.stoptiming(instance)
end
end
@@ -4476,7 +4925,7 @@ if texconfig and not texlua then
t = {
utftype = u, -- may go away
lines = l,
- current = 0,
+ current = 0, -- line number, not really needed
handle = nil,
noflines = #l,
close = function()
@@ -4484,15 +4933,23 @@ if texconfig and not texlua then
input.show_close(filename)
end,
reader = function(self)
- if not self then self = t end
- if self.current >= #self.lines then
+ self = self or t
+ local current, lines = self.current, self.lines
+ if current >= #lines then
return nil
else
- self.current = self.current + 1
- if input.filters.utf_translator then
- return input.filters.utf_translator(self.lines[t.current])
+ self.current = current + 1
+ local line = lines[self.current]
+ if line == "" then
+ return ""
else
- return self.lines[self.current]
+ local translator = input.filters.utf_translator
+ -- return (translator and translator(line)) or line
+ if translator then
+ return translator(line)
+ else
+ return line
+ end
end
end
end
@@ -4502,13 +4959,15 @@ if texconfig and not texlua then
-- todo: file;name -> freeze / eerste regel scannen -> freeze
t = {
reader = function(self)
- if not self then self = t end -- not used
- if input.filters.dynamic_translator then
- return input.filters.dynamic_translator(file_handle:read())
+ local line = file_handle:read()
+ if line == "" then
+ return ""
elseif input.filters.utf_translator then
- return input.filters.utf_translator(file_handle:read())
+ return input.filters.utf_translator(line)
+ elseif input.filters.dynamic_translator then
+ return input.filters.dynamic_translator(line)
else
- return file_handle:read()
+ return line
end
end,
close = function()
@@ -4745,7 +5204,7 @@ if texconfig and not texlua then
luatex.variablenames = {
'main_memory', 'extra_mem_bot', 'extra_mem_top',
- 'buf_size',
+ 'buf_size','expand_depth',
'font_max', 'font_mem_size',
'hash_extra', 'max_strings', 'pool_free', 'pool_size', 'string_vacancies',
'obj_tab_size', 'pdf_mem_size', 'dest_names_size',
@@ -4920,6 +5379,7 @@ own = { }
own.libs = { -- todo: check which ones are really needed
'l-string.lua',
+ 'l-lpeg.lua',
'l-table.lua',
'l-io.lua',
'l-number.lua',
@@ -4991,7 +5451,7 @@ input.banner = 'LuaTools | '
utils.report = input.report
input.defaultlibs = { -- not all are needed
- 'l-string.lua', 'l-table.lua', 'l-boolean.lua', 'l-number.lua', 'l-unicode.lua',
+ 'l-string.lua', 'l-lpeg.lua', 'l-table.lua', 'l-boolean.lua', 'l-number.lua', 'l-unicode.lua',
'l-md5.lua', 'l-os.lua', 'l-io.lua', 'l-file.lua', 'l-dir.lua', 'l-utils.lua', 'l-tex.lua',
'luat-lib.lua', 'luat-inp.lua', 'luat-tmp.lua', 'luat-zip.lua', 'luat-tex.lua'
}
@@ -5153,7 +5613,8 @@ function input.my_make_format(instance,texname)
flags[#flags+1] = "--lua=" .. string.quote(luaname)
-- flags[#flags+1] = "--progname=" .. instance.progname -- potential fallback
end
- local command = "luatex ".. table.concat(flags," ") .. " " .. string.quote(fullname) .. " \\dump"
+ local bs = (environment.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")
os.exec(command)
end
@@ -5163,7 +5624,7 @@ function input.my_make_format(instance,texname)
end
end
-function input.my_run_format(instance,name,data)
+function input.my_run_format(instance,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+$","")
@@ -5189,7 +5650,7 @@ function input.my_run_format(instance,name,data)
if f then
f:close()
-- bug, no .fmt !
- local command = "luatex --fmt=" .. string.quote(barename) .. " --lua=" .. string.quote(luaname) .. " " .. string.quote(data)
+ local command = "luatex --fmt=" .. string.quote(barename) .. " --lua=" .. string.quote(luaname) .. " " .. string.quote(data) .. " " .. string.quote(more)
input.report("running command: " .. command)
os.exec(command)
else
@@ -5227,11 +5688,11 @@ elseif environment.arguments["find-path"] then
elseif environment.arguments["run"] then
input.my_prepare_a(instance) -- ! no need for loading databases
input.verbose = true
- input.my_run_format(instance,environment.files[1] or "",environment.files[2] or "")
+ input.my_run_format(instance,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.verbose = true
- input.my_run_format(instance,environment.arguments["fmt"], environment.files[1] or "")
+ input.my_run_format(instance,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)
diff --git a/scripts/context/lua/mtx-babel.lua b/scripts/context/lua/mtx-babel.lua
index 5ef9ae934..c9855b86a 100644
--- a/scripts/context/lua/mtx-babel.lua
+++ b/scripts/context/lua/mtx-babel.lua
@@ -1,6 +1,12 @@
--- data tables by Thomas A. Schmitz
+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"
+}
-dofile(input.find_file(instance,"luat-log.lua"))
+-- data tables by Thomas A. Schmitz
texmf.instance = instance -- we need to get rid of this / maybe current instance in global table
@@ -9,6 +15,10 @@ scripts.babel = scripts.babel or { }
do
+ local converters = { }
+
+ -- greek
+
local replace_01 = { -- <' * |
a = "á¾…",
h = "ᾕ",
@@ -216,6 +226,7 @@ do
O = "Ὁ",
U = "á½™",
W = "Ὡ",
+ R = "Ῥ",
}
local replace_23 = { -- > *
@@ -301,61 +312,111 @@ do
local skips_01 = lpeg.P("\\") * lpeg.R("az", "AZ")^1
local skips_02 = lpeg.P("[") * (1- lpeg.S("[]"))^1 * lpeg.P("]")
- local stage_01 = (lpeg.P("<'") * lpeg.Cs(1) * lpeg.P('|')) / replace_01
- local stage_02 = (lpeg.P(">'") * lpeg.Cs(1) * lpeg.P('|')) / replace_02
- local stage_03 = (lpeg.P("<`") * lpeg.Cs(1) * lpeg.P('|')) / replace_03
- local stage_04 = (lpeg.P(">`") * lpeg.Cs(1) * lpeg.P('|')) / replace_04
- local stage_05 = (lpeg.P("<~") * lpeg.Cs(1) * lpeg.P('|')) / replace_05
- local stage_06 = (lpeg.P(">~") * lpeg.Cs(1) * lpeg.P('|')) / replace_06
- local stage_07 = (lpeg.P('"\'') * lpeg.Cs(1) ) / replace_07
- local stage_08 = (lpeg.P('"`') * lpeg.Cs(1) ) / replace_08
- local stage_09 = (lpeg.P('"~') * lpeg.Cs(1) ) / replace_09
- local stage_10 = (lpeg.P("<'") * lpeg.Cs(1) ) / replace_10
- local stage_11 = (lpeg.P(">'") * lpeg.Cs(1) ) / replace_11
- local stage_12 = (lpeg.P("<`") * lpeg.Cs(1) ) / replace_12
- local stage_13 = (lpeg.P(">`") * lpeg.Cs(1) ) / replace_13
- local stage_14 = (lpeg.P(">~") * lpeg.Cs(1) ) / replace_14
- local stage_15 = (lpeg.P(">~") * lpeg.Cs(1) ) / replace_15
- local stage_16 = (lpeg.P("'") * lpeg.Cs(1) * lpeg.P('|')) / replace_16
- local stage_17 = (lpeg.P("`") * lpeg.Cs(1) * lpeg.P('|')) / replace_17
- local stage_18 = (lpeg.P("~") * lpeg.Cs(1) * lpeg.P('|')) / replace_18
- local stage_19 = (lpeg.P("'") * lpeg.Cs(1) ) / replace_19
- local stage_20 = (lpeg.P("`") * lpeg.Cs(1) ) / replace_20
- local stage_21 = (lpeg.P("~") * lpeg.Cs(1) ) / replace_21
- local stage_22 = (lpeg.P("<") * lpeg.Cs(1) ) / replace_22
- local stage_23 = (lpeg.P(">") * lpeg.Cs(1) ) / replace_23
- local stage_24 = (lpeg.Cs(1) * lpeg.P('|') ) / replace_24
- local stage_25 = (lpeg.P('"') * lpeg.Cs(1) ) / replace_25
- local stage_26 = (lpeg.Cs(1) ) / replace_26
-
- local stages =
- skips_01 + skips_02 +
- stage_01 + stage_02 + stage_03 + stage_04 + stage_05 +
- stage_06 + stage_07 + stage_08 + stage_09 + stage_10 +
- stage_11 + stage_12 + stage_13 + stage_14 + stage_15 +
- stage_16 + stage_17 + stage_18 + stage_19 + stage_20 +
- stage_21 + stage_22 + stage_23 + stage_24 + stage_25 +
- stage_26
-
- local parser = lpeg.Cs((stages + 1)^0)
+ local greek_01 = (lpeg.P("<'") * lpeg.Cs(1) * lpeg.P('|')) / replace_01
+ local greek_02 = (lpeg.P(">'") * lpeg.Cs(1) * lpeg.P('|')) / replace_02
+ local greek_03 = (lpeg.P("<`") * lpeg.Cs(1) * lpeg.P('|')) / replace_03
+ local greek_04 = (lpeg.P(">`") * lpeg.Cs(1) * lpeg.P('|')) / replace_04
+ local greek_05 = (lpeg.P("<~") * lpeg.Cs(1) * lpeg.P('|')) / replace_05
+ local greek_06 = (lpeg.P(">~") * lpeg.Cs(1) * lpeg.P('|')) / replace_06
+ local greek_07 = (lpeg.P('"\'') * lpeg.Cs(1) ) / replace_07
+ local greek_08 = (lpeg.P('"`') * lpeg.Cs(1) ) / replace_08
+ local greek_09 = (lpeg.P('"~') * lpeg.Cs(1) ) / replace_09
+ local greek_10 = (lpeg.P("<'") * lpeg.Cs(1) ) / replace_10
+ local greek_11 = (lpeg.P(">'") * lpeg.Cs(1) ) / replace_11
+ local greek_12 = (lpeg.P("<`") * lpeg.Cs(1) ) / replace_12
+ local greek_13 = (lpeg.P(">`") * lpeg.Cs(1) ) / replace_13
+ local greek_14 = (lpeg.P("<~") * lpeg.Cs(1) ) / replace_14
+ local greek_15 = (lpeg.P(">~") * lpeg.Cs(1) ) / replace_15
+ local greek_16 = (lpeg.P("'") * lpeg.Cs(1) * lpeg.P('|')) / replace_16
+ local greek_17 = (lpeg.P("`") * lpeg.Cs(1) * lpeg.P('|')) / replace_17
+ local greek_18 = (lpeg.P("~") * lpeg.Cs(1) * lpeg.P('|')) / replace_18
+ local greek_19 = (lpeg.P("'") * lpeg.Cs(1) ) / replace_19
+ local greek_20 = (lpeg.P("`") * lpeg.Cs(1) ) / replace_20
+ local greek_21 = (lpeg.P("~") * lpeg.Cs(1) ) / replace_21
+ local greek_22 = (lpeg.P("<") * lpeg.Cs(1) ) / replace_22
+ local greek_23 = (lpeg.P(">") * lpeg.Cs(1) ) / replace_23
+ local greek_24 = (lpeg.Cs(1) * lpeg.P('|') ) / replace_24
+ local greek_25 = (lpeg.P('"') * lpeg.Cs(1) ) / replace_25
+ local greek_26 = (lpeg.Cs(1) ) / replace_26
+
+ local skips =
+ skips_01 + skips_02
+
+ local greek =
+ greek_01 + greek_02 + greek_03 + greek_04 + greek_05 +
+ greek_06 + greek_07 + greek_08 + greek_09 + greek_10 +
+ greek_11 + greek_12 + greek_13 + greek_14 + greek_15 +
+ greek_16 + greek_17 + greek_18 + greek_19 + greek_20 +
+ greek_21 + greek_22 + greek_23 + greek_24 + greek_25 +
+ greek_26
+
+ local spacing = lpeg.S(" \n\r\t")
+ local startgreek = lpeg.P("\\startgreek")
+ local stopgreek = lpeg.P("\\stopgreek")
+ local localgreek = lpeg.P("\\localgreek")
+ local lbrace = lpeg.P("{")
+ local rbrace = lpeg.P("}")
+
+ local documentparser = lpeg.Cs((skips + greek + 1)^0)
+
+ local contextgrammar = lpeg.Cs ( lpeg.P { "scan",
+ ["scan"] = (lpeg.V("global") + lpeg.V("local") + skips + 1)^0,
+ ["global"] = startgreek * ((skips + greek + 1)-stopgreek )^0 ,
+ ["local"] = localgreek * lpeg.V("grouped"),
+ ["grouped"] = spacing^0 * lbrace * (lpeg.V("grouped") + skips + (greek - rbrace))^0 * rbrace,
+ } )
+
+ converters['greek'] = {
+ document = documentparser,
+ context = contextgrammar,
+ }
-- lpeg.print(parser): 254 lines
function scripts.babel.convert(filename)
if filename and filename ~= empty then
- local data = io.loaddata(filename)
- if data then
- data = parser:match(data)
- io.savedata(filename .. ".utf", data)
+ local data = io.loaddata(filename) or ""
+ if data ~= "" then
+ local language = environment.argument("language") or ""
+ if language ~= "" then
+ local converter = converters[language]
+ if converter then
+ 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))
+ data = converter:match(data)
+ local newfilename = filename .. ".utf"
+ io.savedata(newfilename, data)
+ input.report(string.format("converted data saved in '%s'", newfilename))
+ else
+ input.report(string.format("unknown structure '%s' language '%s'", structure, language))
+ end
+ else
+ input.report(string.format("no converter for language '%s'", language))
+ end
+ else
+ input.report(string.format("provide language"))
+ end
+ else
+ input.report(string.format("no data in '%s'",filename))
end
end
end
+ --~ print(contextgrammar:match [[
+ --~ oeps abg \localgreek{a}
+ --~ \startgreek abg \stopgreek \oeps
+ --~ oeps abg \localgreek{a{b}\oeps g}
+ --~ ]])
+
end
-banner = banner .. " | conversion tools "
+banner = banner .. " | babel conversion tools "
messages.help = [[
+--language=string conversion language (e.g. greek)
+--structure=string obey given structure (e.g. 'document', default: 'context')
--convert convert babel codes into utf
]]
@@ -366,3 +427,4 @@ 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 8bd3b7a79..0fdaca6a4 100644
--- a/scripts/context/lua/mtx-cache.lua
+++ b/scripts/context/lua/mtx-cache.lua
@@ -1,4 +1,10 @@
-dofile(input.find_file(instance,"luat-log.lua"))
+if not modules then modules = { } end modules ['mtx-cache'] = {
+ version = 1.001,
+ comment = "companion to mtxrun.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
texmf.instance = instance -- we need to get rid of this / maybe current instance in global table
diff --git a/scripts/context/lua/mtx-chars.lua b/scripts/context/lua/mtx-chars.lua
index 470846419..77c74cf51 100644
--- a/scripts/context/lua/mtx-chars.lua
+++ b/scripts/context/lua/mtx-chars.lua
@@ -1,4 +1,10 @@
-dofile(input.find_file(instance,"luat-log.lua"))
+if not modules then modules = { } end modules ['mtx-chars'] = {
+ version = 1.001,
+ comment = "companion to mtxrun.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
texmf.instance = instance -- we need to get rid of this / maybe current instance in global table
diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua
index c444dfd1a..2e7855847 100644
--- a/scripts/context/lua/mtx-context.lua
+++ b/scripts/context/lua/mtx-context.lua
@@ -1,4 +1,10 @@
-dofile(input.find_file(instance,"luat-log.lua"))
+if not modules then modules = { } end modules ['mtx-context'] = {
+ version = 1.001,
+ comment = "companion to mtxrun.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
texmf.instance = instance -- we need to get rid of this / maybe current instance in global table
@@ -468,9 +474,11 @@ function scripts.context.multipass.makeoptionfile(jobname,ctxdata)
setvalues("usemodules" , "\\usemodule[%s]")
setvalues("environments" , "\\environment %s ")
-- ctx stuff
- setvalues(ctxdata.modes, "\\enablemode[%s]")
- setvalues(ctxdata.modules, "\\usemodule[%s]")
- setvalues(ctxdata.environments, "\\environment %s ")
+ if ctxdata then
+ setvalues(ctxdata.modes, "\\enablemode[%s]")
+ setvalues(ctxdata.modules, "\\usemodule[%s]")
+ setvalues(ctxdata.environments, "\\environment %s ")
+ end
-- done
setalways( "\\protect")
setalways( "\\endinput")
@@ -497,11 +505,12 @@ function scripts.context.multipass.copytuifile(jobname)
end
function scripts.context.run(ctxdata)
- -- todo: interface
-for k,v in pairs(ctxdata.flags) do
- environment.setargument(k,v)
-end
-
+ if ctxdata then
+ -- todo: interface
+ for k,v in pairs(ctxdata.flags) do
+ environment.setargument(k,v)
+ end
+ end
local files = environment.files
if #files > 0 then
input.identify_cnf(instance)
diff --git a/scripts/context/lua/mtx-convert.lua b/scripts/context/lua/mtx-convert.lua
new file mode 100644
index 000000000..c9827c8b7
--- /dev/null
+++ b/scripts/context/lua/mtx-convert.lua
@@ -0,0 +1,86 @@
+if not modules then modules = { } end modules ['mtx-convert'] = {
+ 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"
+}
+
+do
+
+ graphics = graphics or { }
+ graphics.converters = graphics.converters or { }
+
+ 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.execute(command)
+ os.remove(newname)
+ os.rename(tmpname,newname)
+ end
+ end
+
+ function graphics.converters.convertpath(inputpath,outputpath)
+ for name in lfs.dir(inputpath or ".") do
+ 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
+ graphics.converters.convertpath(inputpath .. "/".. name,outputpath .. "/".. name)
+ end
+ end
+ end
+
+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 { }
+
+scripts.convert.delay = 5 * 60 -- 5 minutes
+
+function scripts.convert.convertall()
+ local watch = environment.arguments.watch or false
+ local delay = environment.arguments.delay or scripts.convert.delay
+ local input = environment.arguments.inputpath or "."
+ local output = environment.arguments.outputpath or "."
+ while true do
+ graphics.converters.convertpath(input, output)
+ if watch then
+ os.sleep(delay)
+ else
+ break
+ end
+ end
+end
+
+banner = banner .. " | graphic conversion tools "
+
+messages.help = [[
+--convertall convert all graphics on path
+--inputpath=string original graphics path
+--outputpath=string converted graphics path
+--watch watch folders
+--delay time between sweeps
+]]
+
+input.verbose = true
+
+if environment.argument("convertall") then
+ scripts.convert.convertall()
+else
+ input.help(banner,messages.help)
+end
diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua
index ba5215ab1..395e9764e 100644
--- a/scripts/context/lua/mtx-fonts.lua
+++ b/scripts/context/lua/mtx-fonts.lua
@@ -1,4 +1,11 @@
-dofile(input.find_file(instance,"luat-log.lua"))
+if not modules then modules = { } end modules ['mtx-fonts'] = {
+ 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"
+}
+
dofile(input.find_file(instance,"font-syn.lua"))
texmf.instance = instance -- we need to get rid of this / maybe current instance in global table
diff --git a/scripts/context/lua/mtx-watch.lua b/scripts/context/lua/mtx-watch.lua
new file mode 100644
index 000000000..651865ab4
--- /dev/null
+++ b/scripts/context/lua/mtx-watch.lua
@@ -0,0 +1,224 @@
+if not modules then modules = { } end modules ['mtx-watch'] = {
+ version = 1.001,
+ comment = "companion to mtxrun.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+texmf.instance = instance -- we need to get rid of this / maybe current instance in global table
+
+scripts = scripts or { }
+scripts.watch = scripts.watch or { }
+
+function scripts.watch.watch()
+ local delay = environment.argument("delay") or 5
+ local logpath = environment.argument("logpath") or ""
+ local pipe = environment.argument("pipe") or false
+ if #environment.files > 0 then
+ for _, path in ipairs(environment.files) do
+ logs.report("watch", "watching path ".. path)
+ end
+ local function glob(files,path)
+ for name in lfs.dir(path) do
+ if name:find("^%.") then
+ -- skip . and ..
+ else
+ name = path .. "/" .. name
+ local a = lfs.attributes(name)
+ if not a then
+ -- weird
+ elseif a.mode == "directory" then
+ if name:find("graphics$") or name:find("figures$") or name:find("resources$") then
+ -- skip these too
+ else
+ glob(files,name)
+ end
+ elseif name:find(".%luj$") then
+ files[name] = a.change or a.ctime or a.modification or a.mtime
+ end
+ end
+ end
+ end
+ local n = 0
+ local function process()
+ local done = false
+ for _, path in ipairs(environment.files) do
+ lfs.chdir(path)
+ local files = { }
+ glob(files,path)
+ table.sort(files) -- what gets sorted here
+ for name, time in pairs(files) do
+ --~ local ok, joblog = xpcall(function() return dofile(name) end, function() end )
+ local ok, joblog = pcall(dofile,name)
+ if ok and joblog then
+ if joblog.status == "processing" then
+ logs.report("watch",string.format("aborted job, %s added to queue",name))
+ joblog.status = "queued"
+ io.savedata(name, table.serialize(joblog,true))
+ elseif joblog.status == "queued" then
+ local command = joblog.command
+ if command then
+ local replacements = {
+ inputpath = (joblog.paths and joblog.paths.input ) or ".",
+ outputpath = (joblog.paths and joblog.paths.output) or ".",
+ filename = joblog.filename or "",
+ }
+ command = command:gsub("%%(.-)%%", replacements)
+ if command ~= "" then
+ joblog.status = "processing"
+ joblog.runtime = os.time() -- os.clock()
+ io.savedata(name, table.serialize(joblog,true))
+ logs.report("watch",string.format("running: %s", command))
+ local newpath = file.dirname(name)
+ io.flush()
+ local result = ""
+ if newpath ~= "" and newpath ~= "." then
+ local oldpath = lfs.currentdir()
+ lfs.chdir(newpath)
+ if pipe then result = os.resultof(command) else result = os.execute(command) end
+ lfs.chdir(oldpath)
+ else
+ if pipe then result = os.resultof(command) else result = os.execute(command) end
+ end
+ logs.report("watch",string.format("return value: %s", result))
+ done = true
+ local path, base = replacements.outputpath, file.basename(replacements.filename)
+ joblog.runtime = os.time() - joblog.runtime -- os.clock() - joblog.runtime
+ joblog.result = file.replacesuffix(file.join(path,base),"pdf")
+ joblog.size = lfs.attributes(joblog.result,"size")
+ joblog.status = "finished"
+ else
+ joblog.status = "invalid command"
+ end
+ else
+ joblog.status = "no command"
+ end
+ -- pcall, when error sleep + again
+ io.savedata(name, table.serialize(joblog,true))
+ if logpath ~= "" then
+ local name = string.format("%s/%s%04i%09i.lua", logpath, os.time(), math.floor((os.clock()*100)%1000), math.random(99999999))
+ io.savedata(name, table.serialize(joblog,true))
+ logs.report("watch", "saving joblog ".. name)
+ end
+ end
+ end
+ end
+ end
+ end
+ local function wait()
+ io.flush()
+ if not done then
+ n = n + 1
+ if n >= 10 then
+ logs.report("watch", "still sleeping " .. os.clock())
+ n = 0
+ end
+ os.sleep(delay)
+ end
+ end
+ while true do
+ pcall(process)
+ pcall(wait)
+ end
+ else
+ logs.report("watch", "no paths to watch")
+ end
+end
+
+function scripts.watch.collect_logs(path) -- clean 'm up too
+ path = path or environment.argument("logpath") or ""
+ path = (path == "" and ".") or path
+ local files = dir.globfiles(path,false,"^%d+%.lua$")
+ local collection = { }
+ local valid = table.tohash({"filename","result","runtime","size","status"})
+ for _, name in ipairs(files) do
+ local t = dofile(name)
+ if t and type(t) == "table" and t.status then
+ for k, v in pairs(t) do
+ if not valid[k] then
+ t[k] = nil
+ end
+ end
+ collection[name:gsub("[^%d]","")] = t
+ end
+ end
+ return collection
+end
+
+function scripts.watch.save_logs(collection,path) -- play safe
+ if collection and not table.is_empty(collection) then
+ path = path or environment.argument("logpath") or ""
+ path = (path == "" and ".") or path
+ local filename = string.format("%s/collected-%s.lua",path,tostring(os.time()))
+ io.savedata(filename,table.serialize(collection,true))
+ local check = dofile(filename)
+ for k,v in pairs(check) do
+ if not collection[k] then
+ logs.error("watch", "error in saving file")
+ os.remove(filename)
+ return false
+ end
+ end
+ for k,v in pairs(check) do
+ os.remove(string.format("%s.lua",k))
+ end
+ return true
+ else
+ return false
+ end
+end
+
+function scripts.watch.collect_collections(path) -- removes duplicates
+ path = path or environment.argument("logpath") or ""
+ path = (path == "" and ".") or path
+ local files = dir.globfiles(path,false,"^collected%-%d+%.lua$")
+ local collection = { }
+ for _, name in ipairs(files) do
+ local t = dofile(name)
+ if t and type(t) == "table" then
+ for k, v in pairs(t) do
+ collection[k] = v
+ end
+ end
+ end
+ return collection
+end
+
+function scripts.watch.show_logs(path) -- removes duplicates
+ local collection = scripts.watch.collect_collections(path) or { }
+ local max = 0
+ for k,v in pairs(collection) do
+ v = v.filename or "?"
+ if #v > max then max = #v end
+ end
+ print(max)
+ for k,v in ipairs(table.sortedkeys(collection)) do
+ local c = collection[v]
+ local f, s, r, n = c.filename or "?", c.status or "?", c.runtime or 0, c.size or 0
+ logs.report("watch", string.format("%s %s %3i %8i %s",string.padd(f,max," "),string.padd(s,10," "),r,n,v))
+ end
+end
+
+banner = banner .. " | watchdog"
+
+messages.help = [[
+--logpath optional path for log files
+--watch watch given path
+--pipe use pipe instead of execute
+--delay delay between sweeps
+--collect condense log files
+--showlog show log data
+]]
+
+input.verbose = true
+
+if environment.argument("watch") then
+ scripts.watch.watch()
+elseif environment.argument("collect") then
+ scripts.watch.save_logs(scripts.watch.collect_logs())
+elseif environment.argument("showlog") then
+ scripts.watch.show_logs()
+else
+ input.help(banner,messages.help)
+end
diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua
index baad28e84..d180fa9b9 100644
--- a/scripts/context/lua/mtxrun.lua
+++ b/scripts/context/lua/mtxrun.lua
@@ -1,5 +1,14 @@
#!/usr/bin/env texlua
+if not modules then modules = { } end modules ['mtxrun'] = {
+ version = 1.001,
+ comment = "runner, lua replacement for texmfstart.rb",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+
-- one can make a stub:
--
-- #!/bin/sh
@@ -29,7 +38,7 @@
-- remember for subruns: _CTX_K_S_#{original}_
-- remember for subruns: TEXMFSTART.#{original} [tex.rb texmfstart.rb]
-banner = "version 1.0.1 - 2007+ - PRAGMA ADE / CONTEXT"
+banner = "version 1.0.2 - 2007+ - PRAGMA ADE / CONTEXT"
texlua = true
-- begin library merge
@@ -370,6 +379,49 @@ function string:split_settings() -- no {} handling, see l-aux for lpeg variant
end
+-- filename : l-lpeg.lua
+-- 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['l-lpeg'] = 1.001
+
+--~ l-lpeg.lua :
+
+--~ lpeg.digit = lpeg.R('09')^1
+--~ lpeg.sign = lpeg.S('+-')^1
+--~ lpeg.cardinal = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.integer = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.float = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
+--~ lpeg.number = lpeg.float + lpeg.integer
+--~ lpeg.oct = lpeg.P("0") * lpeg.R('07')^1
+--~ lpeg.hex = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
+--~ lpeg.uppercase = lpeg.P("AZ")
+--~ lpeg.lowercase = lpeg.P("az")
+
+--~ lpeg.eol = lpeg.S('\r\n\f')^1 -- includes formfeed
+--~ lpeg.space = lpeg.S(' ')^1
+--~ lpeg.nonspace = lpeg.P(1-lpeg.space)^1
+--~ lpeg.whitespace = lpeg.S(' \r\n\f\t')^1
+--~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
+
+function lpeg.anywhere(pattern) --slightly adapted from website
+ return lpeg.P { lpeg.P(pattern) + 1 * lpeg.V(1) }
+end
+
+function lpeg.startswith(pattern) --slightly adapted
+ return lpeg.P(pattern)
+end
+
+--~ g = lpeg.splitter(" ",function(s) ... end) -- gmatch:lpeg = 3:2
+
+function lpeg.splitter(pattern, action)
+ return (((1-lpeg.P(pattern))^1)/action+1)^0
+end
+
+
+
+
-- filename : l-table.lua
-- comment : split off from luat-lib
-- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
@@ -443,6 +495,7 @@ function table.merge(t, ...)
t[k] = v
end
end
+ return t
end
function table.merged(...)
@@ -455,6 +508,25 @@ function table.merged(...)
return tmp
end
+function table.imerge(t, ...)
+ for _, list in ipairs({...}) do
+ for k,v in ipairs(list) do
+ t[#t+1] = v
+ end
+ end
+ return t
+end
+
+function table.imerged(...)
+ local tmp = { }
+ for _, list in ipairs({...}) do
+ for _,v in pairs(list) do
+ tmp[#tmp+1] = v
+ end
+ end
+ return tmp
+end
+
if not table.fastcopy then
function table.fastcopy(old) -- fast one
@@ -1101,6 +1173,38 @@ do
end
+function io.ask(question,default,options)
+ while true do
+ io.write(question)
+ if options then
+ io.write(string.format(" [%s]",table.concat(options,"|")))
+ end
+ if default then
+ io.write(string.format(" [%s]",default))
+ end
+ io.write(string.format(" "))
+ local answer = io.read()
+ answer = answer:gsub("^%s*(.*)%s*$","%1")
+ if answer == "" and default then
+ return default
+ elseif not options then
+ return answer
+ else
+ for _,v in pairs(options) do
+ if v == answer then
+ return answer
+ end
+ end
+ local pattern = "^" .. answer
+ for _,v in pairs(options) do
+ if v:find(pattern) then
+ return v
+ end
+ end
+ end
+ end
+end
+
-- filename : l-md5.lua
-- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
@@ -1117,7 +1221,7 @@ if md5 then do
if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end
if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end
- if not md5.dec then function md5.dec(str) return convert(stt,"%03i") end end
+ if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end
end end
@@ -1325,15 +1429,18 @@ dir = { }
if lfs then
function dir.glob_pattern(path,patt,recurse,action)
- for name in lfs.dir(path) do
- local full = path .. '/' .. name
- local mode = lfs.attributes(full,'mode')
- if mode == 'file' then
- if name:find(patt) then
- action(full)
+ local ok, scanner = xpcall(function() return lfs.dir(path) end, function() end) -- kepler safe
+ if ok and type(scanner) == "function" then
+ for name in scanner do
+ local full = path .. '/' .. name
+ local mode = lfs.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
+ dir.glob_pattern(full,patt,recurse,action)
end
- elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
- dir.glob_pattern(full,patt,recurse,action)
end
end
end
@@ -1358,6 +1465,30 @@ if lfs then
return t
end
+ function dir.globfiles(path,recurse,func,files)
+ if type(func) == "string" then
+ local s = func -- alas, we need this indirect way
+ func = function(name) return name:find(s) end
+ end
+ files = files or { }
+ for name in lfs.dir(path) do
+ if name:find("^%.") then
+ --- skip
+ elseif lfs.attributes(name,'mode') == "directory" then
+ if recurse then
+ dir.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
+ end
+ end
+ return files
+ end
+
-- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
-- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
-- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
@@ -1374,35 +1505,25 @@ if lfs then
--~ mkdirs(".","/a/b/c")
--~ mkdirs("a","b","c")
- function dir.mkdirs(...) -- root,... or ... ; root is not split
- local pth, err = "", false
- for k,v in pairs({...}) do
- if k == 1 then
- if not lfs.isdir(v) then
- -- print("no root path " .. v)
- err = true
- else
- pth = v
- end
- elseif lfs.isdir(pth .. "/" .. v) then
- pth = pth .. "/" .. v
+ function dir.mkdirs(...)
+ local pth, err, lst = "", false, table.concat({...},"/")
+ for _, s in ipairs(lst:split("/")) do
+ if pth == "" then
+ pth = (s == "" and "/") or s
else
- for _,s in pairs(v:split("/")) do
- pth = pth .. "/" .. s
- if not lfs.isdir(pth) then
- ok = lfs.mkdir(pth)
- if not lfs.isdir(pth) then
- err = true
- end
- end
- if err then break end
- end
+ pth = pth .. "/" .. s
+ end
+ if s == "" then
+ -- can be network path
+ elseif not lfs.isdir(pth) then
+ lfs.mkdir(pth)
end
- if err then break end
end
return pth, not err
end
+ dir.makedirs = dir.mkdirs
+
end
@@ -1512,7 +1633,8 @@ xml.xmlns = { }
do
- local parser = lpeg.P(false) -- printing shows that this has no side effects
+ local check = lpeg.P(false)
+ local parse = check
--[[ldx--
<p>The next function associates a namespace prefix with an <l n='url'/>. This
@@ -1524,7 +1646,8 @@ do
--ldx]]--
function xml.registerns(namespace, pattern) -- pattern can be an lpeg
- parser = parser + lpeg.C(lpeg.P(pattern:lower())) / namespace
+ check = check + lpeg.C(lpeg.P(pattern:lower())) / namespace
+ parse = lpeg.P { lpeg.P(check) + 1 * lpeg.V(1) }
end
--[[ldx--
@@ -1538,7 +1661,7 @@ do
--ldx]]--
function xml.checkns(namespace,url)
- local ns = parser:match(url:lower())
+ local ns = parse:match(url:lower())
if ns and namespace ~= ns then
xml.xmlns[namespace] = ns
end
@@ -1556,7 +1679,7 @@ do
--ldx]]--
function xml.resolvens(url)
- return parser:match(url:lower()) or ""
+ return parse:match(url:lower()) or ""
end
--[[ldx--
@@ -1607,11 +1730,15 @@ do
local mt = { __tostring = xml.text }
+ function xml.check_error(top,toclose)
+ return ""
+ end
+
local function add_attribute(namespace,tag,value)
if tag == "xmlns" then
xmlns[#xmlns+1] = xml.resolvens(value)
at[tag] = value
- elseif ns == "xmlns" then
+ elseif namespace == "xmlns" then
xml.checkns(tag,value)
at["xmlns:" .. tag] = value
else
@@ -1623,7 +1750,7 @@ do
dt[#dt+1] = spacing
end
local resolved = (namespace == "" and xmlns[#xmlns]) or nsremap[namespace] or namespace
- top = { ns=namespace or "", nr=resolved, tg=tag, at=at, dt={}, __p__ = stack[#stack] }
+ top = { ns=namespace or "", rn=resolved, tg=tag, at=at, dt={}, __p__ = stack[#stack] }
setmetatable(top, mt)
dt = top.dt
stack[#stack+1] = top
@@ -1636,9 +1763,9 @@ do
local toclose = remove(stack)
top = stack[#stack]
if #stack < 1 then
- errorstr = string.format("nothing to close with %s", tag)
+ errorstr = string.format("nothing to close with %s %s", tag, xml.check_error(top,toclose) or "")
elseif toclose.tg ~= tag then -- no namespace check
- errorstr = string.format("unable to close %s with %s", toclose.tg, tag)
+ errorstr = string.format("unable to close %s with %s %s", toclose.tg, tag, xml.check_error(top,toclose) or "")
end
dt = top.dt
dt[#dt+1] = toclose
@@ -1654,7 +1781,7 @@ do
top = stack[#stack]
setmetatable(top, mt)
dt = top.dt
- dt[#dt+1] = { ns=namespace or "", nr=resolved, tg=tag, at=at, dt={}, __p__ = top }
+ dt[#dt+1] = { ns=namespace or "", rn=resolved, tg=tag, at=at, dt={}, __p__ = top }
at = { }
if at.xmlns then
remove(xmlns)
@@ -1743,14 +1870,13 @@ do
-- text + comment + emptyelement + cdata + instruction + lpeg.V("parent"), -- 5.8
-- text + lpeg.V("parent") + emptyelement + comment + cdata + instruction, -- 5.5
-
local grammar = lpeg.P { "preamble",
preamble = utfbom^0 * instruction^0 * (doctype + comment + instruction)^0 * lpeg.V("parent") * trailer,
parent = beginelement * lpeg.V("children")^0 * endelement,
children = text + lpeg.V("parent") + emptyelement + comment + cdata + instruction,
}
- function xml.convert(data, no_root) -- no collapse any more
+ function xml.convert(data, no_root)
stack, top, at, xmlns, errorstr, result = {}, {}, {}, {}, nil, nil
stack[#stack+1] = top
top.dt = { }
@@ -1761,7 +1887,7 @@ do
errorstr = "invalid xml file"
end
if errorstr then
- result = { dt = { { ns = "", tg = "error", dt = { errorstr }, at={} } } }
+ result = { dt = { { ns = "", tg = "error", dt = { errorstr }, at={}, er = true } }, error = true }
setmetatable(stack, mt)
if xml.error_handler then xml.error_handler("load",errorstr) end
else
@@ -1785,6 +1911,10 @@ do
function. Maybe it will go away (when not used).</p>
--ldx]]--
+ function xml.is_valid(root)
+ return root and root.dt and root.dt[1] and type(root.dt[1]) == "table" and not root.dt[1].er
+ end
+
function xml.package(tag,attributes,data)
local ns, tg = tag:match("^(.-):?([^:]+)$")
local t = { ns = ns, tg = tg, dt = data or "", at = attributes or {} }
@@ -1792,6 +1922,10 @@ do
return t
end
+ function xml.is_valid(root)
+ return root and not root.error
+ end
+
xml.error_handler = (logs and logs.report) or print
end
@@ -1804,16 +1938,18 @@ a filename or a file handle.</p>
function xml.load(filename)
if type(filename) == "string" then
- local root, f = { }, io.open(filename,'r')
+ local f = io.open(filename,'r')
if f then
- root = xml.convert(f:read("*all"))
+ local root = xml.convert(f:read("*all"))
f:close()
+ return root
else
- -- if we want an error: root = xml.convert("")
+ return xml.convert("")
end
- return root -- no nil but an empty table if it fails
- else
+ elseif filename then -- filehandle
return xml.convert(filename:read("*all"))
+ else
+ return xml.convert("")
end
end
@@ -1955,10 +2091,10 @@ do
else
if ats then
-- handle(format("<%s:%s %s/>",ens,etg,table.concat(ats," ")))
- handle("<%" .. ens .. ":" .. etg .. table.concat(ats," ") .. "/>")
+ handle("<" .. ens .. ":" .. etg .. table.concat(ats," ") .. "/>")
else
-- handle(format("<%s:%s/>",ens,etg))
- handle("<%" .. ens .. ":" .. "/>")
+ handle("<" .. ens .. ":" .. "/>")
end
end
else
@@ -2159,9 +2295,20 @@ do
[28] = "has value",
[29] = "fast match",
[30] = "select",
+ [31] = "expression",
[40] = "processing instruction",
}
+ local function make_expression(str)
+ str = str:gsub("@([a-zA-Z%-_]+)", "(a['%1'] or '')")
+ str = str:gsub("position%(%)", "i")
+ str = str:gsub("text%(%)", "t")
+ str = str:gsub("!=", "~=")
+ str = str:gsub("([^=!~<>])=([^=!~<>])", "%1==%2")
+ str = str:gsub("([a-zA-Z%-_]+)%(", "functions.%1(")
+ return str, loadstring(string.format("return function(functions,i,a,t) return %s end", str))()
+ end
+
local map = { }
local space = lpeg.S(' \r\n\t')
@@ -2182,7 +2329,7 @@ do
local bar = lpeg.P('|')
local hat = lpeg.P('^')
local valid = lpeg.R('az', 'AZ', '09') + lpeg.S('_-')
- local name_yes = lpeg.C(valid^1) * colon * lpeg.C(valid^1)
+ local name_yes = lpeg.C(valid^1) * colon * lpeg.C(valid^1 + star) -- permits ns:*
local name_nop = lpeg.C(lpeg.P(true)) * lpeg.C(valid^1)
local name = name_yes + name_nop
local number = lpeg.C((lpeg.S('+-')^0 * lpeg.R('09')^1)) / tonumber
@@ -2202,6 +2349,11 @@ do
local is_value = lbracket * value * rbracket
local is_number = lbracket * number * rbracket
+ local nobracket = 1-(lbracket+rbracket) -- must be improved
+ local is_expression = lbracket * lpeg.C(((lpeg.C(nobracket^1))/make_expression)) * rbracket
+
+ local is_expression = lbracket * (lpeg.C(nobracket^1))/make_expression * rbracket
+
local is_one = name
local is_none = exclam * name
local is_one_of = ((lparent * names * rparent) + morenames)
@@ -2237,6 +2389,9 @@ do
local position = (is_one * is_number ) / function(...) map[#map+1] = { 30, true, ... } end
local dont_position = (is_none * is_number ) / function(...) map[#map+1] = { 30, false, ... } end
+ local expression = (is_one * is_expression)/ function(...) map[#map+1] = { 31, true, ... } end
+ local dont_expression = (is_none * is_expression)/ function(...) map[#map+1] = { 31, false, ... } end
+
local instruction = (instructiontag * text ) / function(...) map[#map+1] = { 40, ... } end
local nothing = (empty ) / function( ) map[#map+1] = { 15 } end -- 15 ?
local crap = (1-slash)^1
@@ -2261,6 +2416,7 @@ do
match_one_of_and_eq + match_one_of_and_ne +
dont_match_and_eq + dont_match_and_ne +
match_and_eq + match_and_ne +
+ dont_expression + expression +
has_attribute + has_value +
dont_match_one_of + match_one_of +
dont_match + match +
@@ -2294,8 +2450,10 @@ do
-- root
return false
end
- elseif #map == 2 and m == 12 and map[2][1] == 20 then
- return { { 29, map[2][2], map[2][3] } }
+ elseif #map == 2 and m == 12 and map[2][1] == 20 then
+ -- return { { 29, map[2][2], map[2][3], map[2][4], map[2][5] } }
+ map[2][1] = 29
+ return { map[2] }
end
if m ~= 11 and m ~= 12 and m ~= 13 and m ~= 14 and m ~= 15 and m ~= 16 then
table.insert(map, 1, { 16 })
@@ -2355,6 +2513,20 @@ do
end
end
+ function xml.xshow(e,...) -- also handy when report is given, use () to isolate first e
+ local t = { ... }
+ local report = (type(t[#t]) == "function" and t[#t]) or fallbackreport
+ if not e then
+ report("<!-- no element -->\n")
+ elseif e.tg then
+ report(tostring(e) .. "\n")
+ else
+ for i=1,#e do
+ report(tostring(e[i]) .. "\n")
+ end
+ end
+ end
+
end
--[[ldx--
@@ -2372,8 +2544,22 @@ advance what we want to do with the found element the handle gets three argument
functions.</p>
--ldx]]--
+xml.functions = { }
+
do
+ local functions = xml.functions
+
+ functions.contains = string.find
+ functions.find = string.find
+ functions.upper = string.upper
+ functions.lower = string.lower
+ functions.number = tonumber
+ functions.boolean = toboolean
+ functions.oneof = function(s,...) -- slow
+ local t = {...} for i=1,#t do if s == t[i] then return true end end return false
+ end
+
function xml.traverse(root,pattern,handle,reverse,index,parent,wildcard)
if not root then -- error
return false
@@ -2402,8 +2588,10 @@ do
local rootdt = root.dt
for k=1,#rootdt do
local e = rootdt[k]
- local ns, tg = e.rn or e.ns, e.tg
- if ns == action[2] and tg == action[3] then
+ local ns, tg = (e.rn or e.ns), e.tg
+ local matched = ns == action[3] and tg == action[4]
+ if not action[2] then matched = not matched end
+ if matched then
if handle(root,rootdt,k) then return false end
end
end
@@ -2416,7 +2604,8 @@ do
end
else
if (command == 16 or command == 12) and index == 1 then -- initial
- wildcard = true
+--~ wildcard = true
+ wildcard = command == 16 -- ok?
index = index + 1
action = pattern[index]
command = action and action[1] or 0 -- something is wrong
@@ -2440,13 +2629,16 @@ do
elseif reverse and index == #pattern then
start, stop, step = stop, start, -1
end
+ local idx = 0
for k=start,stop,step do
local e = rootdt[k]
local ns, tg = e.rn or e.ns, e.tg
if tg then
+ idx = idx + 1
if command == 30 then
- local matched = ns == action[3] and tg == action[4]
- if action[2] then matched = not matched end
+ local tg_a = action[4]
+ if tg == tg_a then matched = ns == action[3] elseif tg_a == '*' then matched, multiple = ns == action[3], true else matched = false end
+ if not action[2] then matched = not matched end
if matched then
n = n + dn
if n == action[5] then
@@ -2463,46 +2655,58 @@ do
else
local matched, multiple = false, false
if command == 20 then -- match
- matched = ns == action[2] and tg == action[3]
- if action[2] then matched = not matched end
+ local tg_a = action[4]
+ if tg == tg_a then matched = ns == action[3] elseif tg_a == '*' then matched, multiple = ns == action[3], true else matched = false end
+ if not action[2] then matched = not matched end
elseif command == 21 then -- match one of
multiple = true
- for i=2,#action,2 do
+ for i=3,#action,2 do
if ns == action[i] and tg == action[i+1] then matched = true break end
end
- if action[2] then matched = not matched end
+ if not action[2] then matched = not matched end
elseif command == 22 then -- eq
- matched = ns == action[3] and tg == action[4]
- if action[2] then matched = not matched end
+ local tg_a = action[4]
+ if tg == tg_a then matched = ns == action[3] elseif tg_a == '*' then matched, multiple = ns == action[3], true else matched = false end
+ if not action[2] then matched = not matched end
matched = matched and e.at[action[6]] == action[7]
elseif command == 23 then -- ne
- matched = ns == action[3] and tg == action[4]
- if action[2] then matched = not matched end
+ local tg_a = action[4]
+ if tg == tg_a then matched = ns == action[3] elseif tg_a == '*' then matched, multiple = ns == action[3], true else matched = false end
+ if not action[2] then matched = not matched end
matched = mached and e.at[action[6]] ~= action[7]
elseif command == 24 then -- one of eq
multiple = true
for i=3,#action-2,2 do
if ns == action[i] and tg == action[i+1] then matched = true break end
end
- if action[2] then matched = not matched end
+ if not action[2] then matched = not matched end
matched = matched and e.at[action[#action-1]] == action[#action]
elseif command == 25 then -- one of ne
multiple = true
for i=3,#action-2,2 do
if ns == action[i] and tg == action[i+1] then matched = true break end
end
- if action[2] then matched = not matched end
+ if not action[2] then matched = not matched end
matched = matched and e.at[action[#action-1]] ~= action[#action]
elseif command == 27 then -- has attribute
- local ans = action[3]
- matched = ns == action[3] and tg == action[4]
- if action[2] then matched = not matched end
+ local tg_a = action[4]
+ if tg == tg_a then matched = ns == action[3] elseif tg_a == '*' then matched, multiple = ns == action[3], true else matched = false end
+ if not action[2] then matched = not matched end
matched = matched and e.at[action[5]]
elseif command == 28 then -- has value
local edt = e.dt
- matched = ns == action[3] and tg == action[4]
- if action[2] then matched = not matched end
+ local tg_a = action[4]
+ if tg == tg_a then matched = ns == action[3] elseif tg_a == '*' then matched, multiple = ns == action[3], true else matched = false end
+ if not action[2] then matched = not matched end
matched = matched and edt and edt[1] == action[5]
+ elseif command == 31 then
+ local edt = e.dt
+ local tg_a = action[4]
+ if tg == tg_a then matched = ns == action[3] elseif tg_a == '*' then matched, multiple = ns == action[3], true else matched = false end
+ if not action[2] then matched = not matched end
+ if matched then
+ matched = action[6](functions,idx,e.at,edt[1])
+ end
end
if matched then -- combine tg test and at test
if index == #pattern then
@@ -2943,28 +3147,33 @@ do
end
end
- function xml.include(xmldata,element,attribute,pathlist,collapse)
- element = element or 'ctx:include'
- attribute = attribute or 'name'
- pathlist = pathlist or { '.' }
- -- todo, check op ri
+ function xml.include(xmldata,pattern,attribute,recursive,findfile)
+ -- parse="text" (default: xml), encoding="" (todo)
+ pattern = pattern or 'include'
+ attribute = attribute or 'href'
local function include(r,d,k)
- local ek = d[k]
- local name = (ek.at and ek.at[attribute]) or ""
- if name ~= "" then
- -- maybe file lookup in tree
- local fullname
- for _, path in ipairs(pathlist) do
- if path == '.' then
- fullname = name
- else
- fullname = file.join(path,name)
- end
- local f = io.open(fullname)
+ local ek, name = d[k], nil
+ if ek.at then
+ for a in attribute:gmatch("([^|]+)") do
+ name = ek.at[a]
+ if name then break end
+ end
+ end
+ if name then
+ name = (findfile and findfile(name)) or name
+ if name ~= "" then
+ local f = io.open(name)
if f then
- xml.assign(d,k,xml.load(f,collapse))
+ if ek.at["parse"] == "text" then -- for the moment hard coded
+ d[k] = xml.escaped(f:read("*all"))
+ else
+ local xi = xml.load(f)
+ if recursive then
+ xml.include(xi,pattern,attribute,recursive,findfile)
+ end
+ xml.assign(d,k,xi)
+ end
f:close()
- break
else
xml.empty(d,k)
end
@@ -2973,7 +3182,7 @@ do
xml.empty(d,k)
end
end
- while xml.each_element(xmldata, element, include) do end
+ xml.each_element(xmldata, pattern, include)
end
function xml.strip_whitespace(root, pattern)
@@ -3041,6 +3250,20 @@ do
end)
end
+ function xml.filters.found(root,pattern,check_content)
+ local found = false
+ traverse(root, lpath(pattern), function(r,d,k)
+ if check_content then
+ local dk = d and d[k]
+ found = dk and dk.dt and next(dk.dt) and true
+ else
+ found = true
+ end
+ return true
+ end)
+ return found
+ end
+
end
--[[ldx--
@@ -3054,6 +3277,7 @@ xml.index = xml.filters.index
xml.position = xml.filters.index
xml.first = xml.filters.first
xml.last = xml.filters.last
+xml.found = xml.filters.found
xml.each = xml.each_element
xml.process = xml.process_element
@@ -3102,12 +3326,46 @@ function xml.serialize_path(root,lpath,handle)
xml.serialize(dk,handle)
end
-xml.escapes = { ['&'] = '&amp;', ['<'] = '&lt;', ['>'] = '&gt;', ['"'] = '&quot;' }
-xml.unescapes = { } for k,v in pairs(xml.escapes) do xml.unescapes[v] = k end
+--~ xml.escapes = { ['&'] = '&amp;', ['<'] = '&lt;', ['>'] = '&gt;', ['"'] = '&quot;' }
+--~ xml.unescapes = { } for k,v in pairs(xml.escapes) do xml.unescapes[v] = k end
-function xml.escaped (str) return str:gsub("(.)" , xml.escapes ) end
-function xml.unescaped(str) return str:gsub("(&.-;)", xml.unescapes) end
-function xml.cleansed (str) return str:gsub("<.->" , '' ) end -- "%b<>"
+--~ function xml.escaped (str) return str:gsub("(.)" , xml.escapes ) end
+--~ function xml.unescaped(str) return str:gsub("(&.-;)", xml.unescapes) end
+--~ function xml.cleansed (str) return str:gsub("<.->" , '' ) end -- "%b<>"
+
+do
+
+ -- 100 * 2500 * "oeps< oeps> oeps&" : gsub:lpeg|lpeg|lpeg
+ --
+ -- 1021:0335:0287:0247
+
+ -- 10 * 1000 * "oeps< oeps> oeps& asfjhalskfjh alskfjh alskfjh alskfjh ;al J;LSFDJ"
+ --
+ -- 1559:0257:0288:0190 (last one suggested by roberto)
+
+ -- escaped = lpeg.Cs((lpeg.S("<&>") / xml.escapes + 1)^0)
+ -- escaped = lpeg.Cs((lpeg.S("<")/"&lt;" + lpeg.S(">")/"&gt;" + lpeg.S("&")/"&amp;" + 1)^0)
+ local normal = (1 - lpeg.S("<&>"))^0
+ local special = lpeg.P("<")/"&lt;" + lpeg.P(">")/"&gt;" + lpeg.P("&")/"&amp;"
+ local escaped = lpeg.Cs(normal * (special * normal)^0)
+
+ -- 100 * 1000 * "oeps&lt; oeps&gt; oeps&amp;" : gsub:lpeg == 0153:0280:0151:0080 (last one by roberto)
+
+ -- unescaped = lpeg.Cs((lpeg.S("&lt;")/"<" + lpeg.S("&gt;")/">" + lpeg.S("&amp;")/"&" + 1)^0)
+ -- unescaped = lpeg.Cs((((lpeg.P("&")/"") * (lpeg.P("lt")/"<" + lpeg.P("gt")/">" + lpeg.P("amp")/"&") * (lpeg.P(";")/"")) + 1)^0)
+ local normal = (1 - lpeg.S"&")^0
+ local special = lpeg.P("&lt;")/"<" + lpeg.P("&gt;")/">" + lpeg.P("&amp;")/"&"
+ local unescaped = lpeg.Cs(normal * (special * normal)^0)
+
+ -- 100 * 5000 * "oeps <oeps bla='oeps' foo='bar'> oeps </oeps> oeps " : gsub:lpeg == 623:501 msec (short tags, less difference)
+
+ local cleansed = lpeg.Cs(((lpeg.P("<") * (1-lpeg.P(">"))^0 * lpeg.P(">"))/"" + 1)^0)
+
+ function xml.escaped (str) return escaped :match(str) end
+ function xml.unescaped(str) return unescaped:match(str) end
+ function xml.cleansed (str) return cleansed :match(str) end
+
+end
function xml.join(t,separator,lastseparator)
if #t > 0 then
@@ -3193,6 +3451,33 @@ end end
--~ xml.lshow("/../../../a/!(b|c)[@d='e']/f")
--~ xml.lshow("/../../../a/!b[@d!='e']/f")
+--~ x = xml.convert([[
+--~ <a>
+--~ <b n='01'>01</b>
+--~ <b n='02'>02</b>
+--~ <b n='03'>03</b>
+--~ <b n='04'>OK</b>
+--~ <b n='05'>05</b>
+--~ <b n='06'>06</b>
+--~ <b n='07'>ALSO OK</b>
+--~ </a>
+--~ ]])
+
+--~ xml.trace_lpath = true
+
+--~ xml.xshow(xml.first(x,"b[position() > 2 and position() < 5 and text() == 'ok']"))
+--~ xml.xshow(xml.first(x,"b[position() > 2 and position() < 5 and text() == upper('ok')]"))
+--~ xml.xshow(xml.first(x,"b[@n=='03' or @n=='08']"))
+--~ xml.xshow(xml.all (x,"b[number(@n)>2 and number(@n)<6]"))
+--~ xml.xshow(xml.first(x,"b[find(text(),'ALSO')]"))
+
+--~ str = [[
+--~ <?xml version="1.0" encoding="utf-8"?>
+--~ <story line='mojca'>
+--~ <windows>my secret</mouse>
+--~ </story>
+--~ ]]
+
-- filename : l-utils.lua
-- comment : split off from luat-lib
@@ -3500,6 +3785,7 @@ end
-- Beware, loading and saving is overloaded in luat-tmp!
-- todo: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller)
+-- todo: check escaping in find etc, too much, too slow
if not versions then versions = { } end versions['luat-inp'] = 1.001
if not environment then environment = { } end
@@ -3737,7 +4023,7 @@ input.settrace(tonumber(os.getenv("MTX.INPUT.TRACE") or os.getenv("MTX_INPUT_TRA
-- These functions can be used to test the performance, especially
-- loading the database files.
-function input.start_timing(instance)
+function input.starttiming(instance)
if instance then
instance.starttime = os.clock()
if not instance.loadtime then
@@ -3746,7 +4032,7 @@ function input.start_timing(instance)
end
end
-function input.stop_timing(instance, report)
+function input.stoptiming(instance, report)
if instance and instance.starttime then
instance.stoptime = os.clock()
local loadtime = instance.stoptime - instance.starttime
@@ -3760,9 +4046,6 @@ function input.stop_timing(instance, report)
end
end
-input.stoptiming = input.stop_timing
-input.starttiming = input.start_timing
-
function input.elapsedtime(instance)
return string.format("%0.3f",instance.loadtime or 0)
end
@@ -4075,99 +4358,106 @@ function input.generatedatabase(instance,specification)
return input.methodhandler('generators', instance, specification)
end
-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 .. '/'
- else
- full = spec
- end
- for name in directory(full) do
- if name:find("^%.") then
- -- skip
- elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%|%<%>%,%?\n\r\t]") then
- -- texio.write_nl("skipping " .. name)
- -- skip
+do
+
+ 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 .. '/'
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
+ 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
- else
- files[name] = path
- local lower = name:lower()
- if name ~= lower then
- files["remap:"..lower] = name
- r = r + 1
+ 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
end
end
end
end
- end
- action()
- input.report(string.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
- if not small then
- if type(fl) == 'string' then
- files[line] = { fl, path } -- table
- else
- fl[#fl+1] = path
+ action()
+ input.report(string.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
+ if not small then
+ if type(fl) == 'string' then
+ files[line] = { fl, path } -- table
+ else
+ fl[#fl+1] = path
+ end
+ end
+ else
+ files[line] = path -- string
+ local lower = line:lower()
+ if line ~= lower then
+ files["remap:"..lower] = line
end
end
else
- files[line] = path -- string
- local lower = line:lower()
- if line ~= lower then
- files["remap:"..lower] = line
- end
+ path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line
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
@@ -4590,10 +4880,168 @@ end
-- a,b,c/{p,q,r}/d/{x,y,z}//
-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a{b,c}{d,e}f
+-- {a,b,c,d}
+-- {a,b,c/{p,q,r},d}
+-- {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}}
+
+-- 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
+-- fuzzy concatenating we can probably gain a bit with selectively
+-- applying lpeg, but experiments with lpeg parsing this proved not to
+-- work that well; the parsing is ok, but dealing with the resulting
+-- table is a pain because we need to work inside-out recursively
+
+--~ 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 { }
+--~ while true do
+--~ local done = false
+--~ while true do
+--~ ok = false
+--~ str = str:gsub("([^{},]+){([^{}]-)}", function(a,b)
+--~ local t = { }
+--~ for s in b:gmatch("([^,]+)") do
+--~ t[#t+1] = a .. s
+--~ end
+--~ ok, done = true, true
+--~ return "{" .. table.concat(t,",") .. "}"
+--~ end)
+--~ if not ok then break end
+--~ end
+--~ while true do
+--~ ok = false
+--~ str = str:gsub("{([^{}]-)}([^{},]+)", function(a,b)
+--~ local t = { }
+--~ for s in a:gmatch("([^,]+)") do
+--~ t[#t+1] = s .. b
+--~ end
+--~ ok, done = true, true
+--~ return "{" .. table.concat(t,",") .. "}"
+--~ end)
+--~ if not ok then break end
+--~ end
+--~ while true do
+--~ ok = false
+--~ str = str:gsub("([,{]){([^{}]+)}([,}])", function(a,b,c)
+--~ ok, done = true, true
+--~ return a .. b .. c
+--~ end)
+--~ if not ok then break end
+--~ end
+--~ if not done then break end
+--~ end
+--~ while true do
+--~ ok = false
+--~ 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 = true
+--~ return "{" .. table.concat(t,",") .. "}"
+--~ end)
+--~ if not ok then break end
+--~ end
+--~ while true do
+--~ ok = false
+--~ str = str:gsub("{([^{}]-)}", function(a)
+--~ ok = true
+--~ return a
+--~ end)
+--~ if not ok then break end
+--~ end
+--~ if validate then
+--~ for s in str:gmatch("([^,]+)") do
+--~ s = validate(s)
+--~ if s then t[#t+1] = s end
+--~ end
+--~ else
+--~ for s in str:gmatch("([^,]+)") do
+--~ t[#t+1] = s
+--~ end
+--~ end
+--~ return t
+--~ end
+
+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
+ while true do
+ local done = false
+ while true do
+ ok = false
+ str = str:gsub("([^{},]+){([^{}]-)}", function(a,b)
+ local t = { }
+ b:piecewise(",", function(s) t[#t+1] = a .. s end)
+ ok, done = true, true
+ return "{" .. concat(t,",") .. "}"
+ end)
+ if not ok then break end
+ end
+ while true do
+ ok = false
+ str = str:gsub("{([^{}]-)}([^{},]+)", function(a,b)
+ local t = { }
+ a:piecewise(",", function(s) t[#t+1] = s .. b end)
+ ok, done = true, true
+ return "{" .. concat(t,",") .. "}"
+ end)
+ if not ok then break end
+ end
+ while true do
+ ok = false
+ str = str:gsub("([,{]){([^{}]+)}([,}])", function(a,b,c)
+ ok, done = true, true
+ return a .. b .. c
+ end)
+ if not ok then break end
+ end
+ if not done then break end
+ end
+ while true do
+ 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
+ ok = false
+ str = str:gsub("{([^{}]-)}", function(a)
+ ok = true
+ return a
+ end)
+ if not ok then break end
+ end
+ if validate then
+ str:piecewise(",", function(s)
+ s = validate(s)
+ if s then t[#t+1] = s end
+ end)
+ else
+ str:piecewise(",", function(s)
+ t[#t+1] = s
+ end)
+ end
+ return t
+end
function input.aux.expanded_path(instance,pathlist)
-- a previous version fed back into pathlist
- local i, n, oldlist, newlist, ok = 0, 0, { }, { }, false
+ local newlist, ok = { }, false
for _,v in ipairs(pathlist) do
if v:find("[{}]") then
ok = true
@@ -4601,45 +5049,11 @@ function input.aux.expanded_path(instance,pathlist)
end
end
if ok then
- for _,v in ipairs(pathlist) do
- oldlist[#oldlist+1] = (v:gsub("([\{\}])", function(p)
- if p == "{" then
- i = i + 1
- if i > n then n = i end
- return "<" .. (i-1) .. ">"
- else
- i = i - 1
- return "</" .. i .. ">"
- end
- end))
- end
- for i=1,n do
- while true do
- local more = false
- local pattern = "^(.-)<"..(n-i)..">(.-)</"..(n-i)..">(.-)$"
- local t = { }
- for _,v in ipairs(oldlist) do
- local pre, mid, post = v:match(pattern)
- if pre and mid and post then
- more = true
- for vv in string.gmatch(mid..',',"(.-),") do
- if vv == '.' then
- t[#t+1] = pre..post
- else
- t[#t+1] = pre..vv..post
- end
- end
- else
- t[#t+1] = v
- end
- end
- oldlist = t
- if not more then break end
- end
- end
- for _,v in ipairs(oldlist) do
- v = file.collapse_path(v)
- if v ~= "" and not v:find(instance.dummy_path_expr) then newlist[#newlist+1] = v end
+ for _, v in ipairs(pathlist) do
+ input.aux.splitpathexpr(v, newlist, function(s)
+ s = file.collapse_path(s)
+ return s ~= "" and not s:find(instance.dummy_path_expr) and s
+ end)
end
else
for _,v in ipairs(pathlist) do
@@ -4652,6 +5066,83 @@ function input.aux.expanded_path(instance,pathlist)
return newlist
end
+--~ old one, imperfect and not that efficient
+--~
+--~ function input.aux.expanded_path(instance,pathlist)
+--~ -- a previous version fed back into pathlist
+--~ local i, n, oldlist, newlist, ok = 0, 0, { }, { }, false
+--~ for _,v in ipairs(pathlist) do
+--~ if v:find("[{}]") then
+--~ ok = true
+--~ break
+--~ end
+--~ end
+--~ if ok then
+--~ for _,v in ipairs(pathlist) do
+--~ oldlist[#oldlist+1] = (v:gsub("([\{\}])", function(p)
+--~ if p == "{" then
+--~ i = i + 1
+--~ if i > n then n = i end
+--~ return "<" .. (i-1) .. ">"
+--~ else
+--~ i = i - 1
+--~ return "</" .. i .. ">"
+--~ end
+--~ end))
+--~ end
+--~ for i=1,n do
+--~ while true do
+--~ local more = false
+--~ local pattern = "^(.-)<"..(n-i)..">(.-)</"..(n-i)..">(.-)$"
+--~ local t = { }
+--~ for _,v in ipairs(oldlist) do
+--~ local pre, mid, post = v:match(pattern)
+--~ if pre and mid and post then
+--~ more = true
+--~ for vv in string.gmatch(mid..',',"(.-),") do -- (mid, "([^,]+)")
+--~ if vv == '.' then
+--~ t[#t+1] = pre..post
+--~ else
+--~ t[#t+1] = pre..vv..post
+--~ end
+--~ end
+--~ else
+--~ t[#t+1] = v
+--~ end
+--~ end
+--~ oldlist = t
+--~ if not more then break end
+--~ end
+--~ end
+--~ if true then
+--~ -- many dups are possible due to messy resolve / order can be messed up too, brr !
+--~ local ok = { }
+--~ for _,o in ipairs(oldlist) do
+--~ for v in o:gmatch("([^,]+)") do
+--~ if not ok[v] then
+--~ ok[v] = true
+--~ v = file.collapse_path(v)
+--~ if v ~= "" and not v:find(instance.dummy_path_expr) then newlist[#newlist+1] = v end
+--~ end
+--~ end
+--~ end
+--~ else
+--~ for _,v in ipairs(oldlist) do
+--~ v = file.collapse_path(v)
+--~ if v ~= "" and not v:find(instance.dummy_path_expr) then newlist[#newlist+1] = v end
+--~ end
+--~ end
+--~ else
+--~ for _,v in ipairs(pathlist) do
+--~ for vv in string.gmatch(v..',',"(.-),") do
+--~ vv = file.collapse_path(v)
+--~ if vv ~= "" then newlist[#newlist+1] = vv end
+--~ end
+--~ end
+--~ end
+--~ return newlist
+--~ end
+
--~ function input.is_readable(name) -- brrr, get rid of this
--~ return name:find("^zip##") or file.is_readable(name)
--~ end
@@ -4750,24 +5241,51 @@ function input.suffixes_of_format(str)
end
end
-function input.aux.qualified_path(filename) -- make platform dependent / not good yet
- return
- filename:find("^%.+/") or
- filename:find("^/") or
- filename:find("^%a+%:") or
- filename:find("^%a+##")
-end
+--~ function input.aux.qualified_path(filename) -- make platform dependent / not good yet
+--~ return
+--~ filename:find("^%.+/") or
+--~ filename:find("^/") or
+--~ filename:find("^%a+%:") or
+--~ filename:find("^%a+##")
+--~ end
+
+--~ function input.normalize_name(original)
+--~ -- internally we use type##spec##subspec ; this hackery slightly slows down searching
+--~ local str = original or ""
+--~ str = str:gsub("::", "##") -- :: -> ##
+--~ str = str:gsub("^(%a+)://" ,"%1##") -- zip:// -> zip##
+--~ str = str:gsub("(.+)##(.+)##/(.+)","%1##%2##%3") -- ##/spec -> ##spec
+--~ if (input.trace>1) and (original ~= str) then
+--~ input.logger('= normalizer',original.." -> "..str)
+--~ end
+--~ return str
+--~ end
+
+do -- called about 700 times for an empty doc (font initializations etc)
+ -- i need to weed the font files for redundant calls
+
+ local letter = lpeg.R("az","AZ")
+ local separator = lpeg.P("##")
+
+ local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator
+ local normalized = lpeg.Cs(
+ (letter^1*(lpeg.P("://")/"##") * (1-lpeg.P(false))^1) +
+ (lpeg.P("::")/"##" + (1-separator)^1*separator*(1-separator)^1*separator*(lpeg.P("/")/"") + 1)^0
+ )
+
+ -- ./name ../name /name c: zip## (todo: use url internally and get rid of ##)
+ function input.aux.qualified_path(filename)
+ return qualified:match(filename)
+ end
-function input.normalize_name(original)
- -- internally we use type##spec##subspec ; this hackery slightly slows down searching
- local str = original or ""
- str = str:gsub("::", "##") -- :: -> ##
- str = str:gsub("^(%a+)://" ,"%1##") -- zip:// -> zip##
- str = str:gsub("(.+)##(.+)##/(.+)","%1##%2##%3") -- ##/spec -> ##spec
- if (input.trace>1) and (original ~= str) then
- input.logger('= normalizer',original.." -> "..str)
+ -- zip:// -> zip## ; :: -> ## ; aa##bb##/cc -> aa##bb##cc
+ function input.normalize_name(original)
+ local str = normalized:match(original or "")
+ if input.trace > 1 and original ~= str then
+ input.logger('= normalizer',original.." -> "..str)
+ end
+ return str
end
- return str
end
-- split the next one up, better for jit
@@ -5132,13 +5650,13 @@ function input.automount(instance)
end
function input.load(instance)
- input.start_timing(instance)
+ input.starttiming(instance)
input.identify_cnf(instance)
input.load_cnf(instance)
input.expand_variables(instance)
input.load_hash(instance)
input.automount(instance)
- input.stop_timing(instance)
+ input.stoptiming(instance)
end
function input.for_files(instance, command, files, filetype, mustexist)
@@ -5432,7 +5950,7 @@ being written at the same time is small. We also need to extend
luatools with a recache feature.</p>
--ldx]]--
-caches = caches or { }
+caches = caches or { }
dir = dir or { }
texmf = texmf or { }
@@ -5444,9 +5962,20 @@ caches.trace = false
caches.tree = false
caches.temp = caches.temp or os.getenv("TEXMFCACHE") or os.getenv("HOME") or os.getenv("HOMEPATH") or os.getenv("VARTEXMF") or os.getenv("TEXMFVAR") or os.getenv("TMP") or os.getenv("TEMP") or os.getenv("TMPDIR") or nil
caches.paths = caches.paths or { caches.temp }
+caches.force = false
+input.usecache = not toboolean(os.getenv("TEXMFSHARECACHE") or "false",true) -- true
+
+if caches.temp and caches.temp ~= "" and lfs.attributes(caches.temp,"mode") ~= "directory" then
+ if caches.force or io.ask(string.format("Should I create the cache path %s?",caches.temp), "no", { "yes", "no" }) == "yes" then
+ lfs.mkdirs(caches.temp)
+ end
+end
if not caches.temp or caches.temp == "" then
- print("\nFATAL ERROR: NO VALID TEMPORARY PATH\n")
+ print("\nfatal error: there is no valid cache path defined\n")
+ os.exit()
+elseif lfs.attributes(caches.temp,"mode") ~= "directory" then
+ print(string.format("\nfatal error: cache path %s is not a directory\n",caches.temp))
os.exit()
end
@@ -5633,8 +6162,6 @@ end
-- since we want to use the cache instead of the tree, we will now
-- reimplement the saver.
-input.usecache = true
-
function input.aux.save_data(instance, dataname, check)
for cachename, files in pairs(instance[dataname]) do
local name
@@ -5868,12 +6395,143 @@ if lua.bytecode then -- from 0 upwards
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 = 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 = {
+ 'error', 'warning', 'info', 'debug', 'report',
+ 'start', 'stop', 'push', 'pop'
+}
+
+logs.callbacks = {
+ 'start_page_number',
+ 'stop_page_number',
+ 'report_output_pages',
+ 'report_output_log'
+}
+
+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
+
+ 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.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.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
+
+end
+
+logs.set_level('error')
+logs.set_method('tex')
+
+
-- end library merge
own = { }
own.libs = { -- todo: check which ones are really needed
'l-string.lua',
+ 'l-lpeg.lua',
'l-table.lua',
'l-io.lua',
'l-md5.lua',
@@ -5892,6 +6550,7 @@ own.libs = { -- todo: check which ones are really needed
-- 'luat-tex.lua',
-- 'luat-kps.lua',
'luat-tmp.lua',
+ 'luat-log.lua',
}
-- We need this hack till luatex is fixed.
@@ -5953,22 +6612,32 @@ instance.lsrmode = environment.argument("lsr") or false
-- use os.env or environment when available
-function os.setenv(key,value)
- -- todo
-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'))
+--~ 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'))
- 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('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.currentplatform()))
+ 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'))
@@ -5985,23 +6654,25 @@ function input.load_environment(name) -- todo: key=value as well as lua
if line:find("^[%%%#]") then
-- skip comment
else
- local key, how, value = line:match("^(.-)%s*([%<%=%>%?]+)%s*(.*)%s*$")
- value = value:gsub("^%%(.+)%%$", function(v) return os.getenv(v) or "" end)
- if how == "=" or how == "<<" then
- os.setenv(key,value)
- elseif how == "?" or how == "??" then
- os.setenv(key,os.getenv(key) or value)
- elseif how == "<" or how == "+=" then
- if os.getenv(key) then
- os.setenv(key,os.getenv(key) .. io.fileseparator .. value)
- else
- os.setenv(key,value)
- end
- elseif how == ">" or how == "=+" then
- if os.getenv(key) then
- os.setenv(key,value .. io.pathseparator .. os.getenv(key))
- else
- os.setenv(key,value)
+ local key, how, value = line:match("^(.-)%s*([<=>%?]+)%s*(.*)%s*$")
+ if how then
+ value = value:gsub("%%(.-)%%", function(v) return os.getenv(v) or "" end)
+ if how == "=" or how == "<<" then
+ os.setenv(key,value)
+ elseif how == "?" or how == "??" then
+ os.setenv(key,os.getenv(key) or value)
+ elseif how == "<" or how == "+=" then
+ if os.getenv(key) then
+ os.setenv(key,os.getenv(key) .. io.fileseparator .. value)
+ else
+ os.setenv(key,value)
+ end
+ elseif how == ">" or how == "=+" then
+ if os.getenv(key) then
+ os.setenv(key,value .. io.pathseparator .. os.getenv(key))
+ else
+ os.setenv(key,value)
+ end
end
end
end
@@ -6013,7 +6684,7 @@ end
function input.load_tree(tree)
if tree and tree ~= "" then
local setuptex = 'setuptex.tmf'
- if lfs.attributes(tree, mode) == "directory" then -- check if not nil
+ if lfs.attributes(tree, "mode") == "directory" then -- check if not nil
setuptex = tree .. "/" .. setuptex
else
setuptex = tree
@@ -6094,6 +6765,26 @@ function file.savechecksum(name, checksum)
return nil
end
+function os.currentplatform()
+ local currentplatform = "linux"
+ if os.platform == "windows" then
+ currentplatform = "mswin"
+ else
+ local architecture = os.resultof("uname -m")
+ local unixvariant = os.resultof("uname -s")
+ if architecture and architecture:find("x86_64") then
+ currentplatform = "linux-64"
+ elseif unixvariant and unixvariant:find("Darwin") then
+ if architecture and architecture:find("i386") then
+ currentplatform = "osx-intel"
+ else
+ currentplatform = "osx-ppc"
+ end
+ end
+ end
+ return currentplatform
+end
+
-- it starts here
input.runners = { }
@@ -6401,6 +7092,27 @@ function input.runners.edit_script(instance,filename)
end
end
+function input.runners.save_script_session(filename, list)
+ local t = { }
+ for _, key in ipairs(list) do
+ t[key] = environment.arguments[key]
+ end
+ io.savedata(filename,table.serialize(t,true))
+end
+
+function input.runners.load_script_session(filename)
+ if lfs.isfile(filename) then
+ local t = io.loaddata(filename)
+ if t then
+ t = loadstring(t)
+ if t then t = t() end
+ for key, value in pairs(t) do
+ environment.arguments[key] = value
+ end
+ end
+ end
+end
+
input.runners.launchers = {
windows = { },
unix = { }
@@ -6448,6 +7160,15 @@ function input.runners.launch_file(instance,filename)
end
function input.runners.execute_ctx_script(instance,filename)
+ local function found(name)
+ local path = file.dirname(name)
+ if path and path ~= "" then
+ return false
+ else
+ local fullname = own and own.path and file.join(own.path,name)
+ return io.exists(fullname) and fullname
+ end
+ end
local before, after = environment.split_arguments(filename)
local suffix = ""
if not filename:find("%.lua$") then suffix = ".lua" end
@@ -6458,17 +7179,17 @@ function input.runners.execute_ctx_script(instance,filename)
-- mtx-<filename>
if not fullname or fullname == "" then
fullname = "mtx-" .. filename .. suffix
- fullname = input.find_file(instance,fullname)
+ fullname = found(fullname) and input.find_file(instance,fullname)
end
-- mtx-<filename>s
if not fullname or fullname == "" then
fullname = "mtx-" .. filename .. "s" .. suffix
- fullname = input.find_file(instance,fullname)
+ fullname = found(fullname) and input.find_file(instance,fullname)
end
-- mtx-<filename minus trailing s>
if not fullname or fullname == "" then
fullname = "mtx-" .. filename:gsub("s$","") .. suffix
- fullname = input.find_file(instance,fullname)
+ fullname = found(fullname) and input.find_file(instance,fullname)
end
-- that should do it
if fullname and fullname ~= "" then
@@ -6480,8 +7201,23 @@ function input.runners.execute_ctx_script(instance,filename)
elseif state == "run" then
arg = { } for _,v in pairs(after) do arg[#arg+1] = v end
environment.initialize_arguments(arg)
+local loadname = environment.arguments['load']
+if loadname then
+ if type(loadname) ~= "string" then loadname = file.basename(fullname) end
+ loadname = file.replacesuffix(loadname,"cfg")
+ input.runners.load_script_session(loadname)
+end
filename = environment.files[1]
+ if input.verbose then
+ input.report("using script: " .. fullname)
+ end
dofile(fullname)
+local savename = environment.arguments['save']
+if savename and input.runners.save_list and not table.is_empty(input.runners.save_list or { }) then
+ if type(savename) ~= "string" then savename = file.basename(fullname) end
+ savename = file.replacesuffix(savename,"cfg")
+ input.runners.save_script_session(savename, input.runners.save_list)
+end
return true
end
else
diff --git a/scripts/context/lua/scite-ctx.lua b/scripts/context/lua/scite-ctx.lua
deleted file mode 100644
index 82f8599b1..000000000
--- a/scripts/context/lua/scite-ctx.lua
+++ /dev/null
@@ -1,924 +0,0 @@
--- version : 1.0.0 - 07/2005
--- author : Hans Hagen - PRAGMA ADE - www.pragma-ade.com
--- copyright : public domain or whatever suits
--- remark : part of the context distribution
-
--- todo: name space for local functions
-
--- loading: scite-ctx.properties
-
--- # environment variable
--- #
--- # CTXSPELLPATH=t:/spell
--- #
--- # auto language detection
--- #
--- # % version =1.0 language=uk
--- # <?xml version='1.0' language='uk' ?>
-
--- ext.lua.startup.script=$(SciteDefaultHome)/scite-ctx.lua
---
--- # extension.$(file.patterns.context)=scite-ctx.lua
--- # extension.$(file.patterns.example)=scite-ctx.lua
---
--- # ext.lua.reset=1
--- # ext.lua.auto.reload=1
--- # ext.lua.startup.script=t:/lua/scite-ctx.lua
---
--- ctx.menulist.default=\
--- wrap=wrap_text|\
--- unwrap=unwrap_text|\
--- sort=sort_text|\
--- document=document_text|\
--- quote=quote_text|\
--- compound=compound_text|\
--- check=check_text
---
--- ctx.spellcheck.language=auto
--- ctx.spellcheck.wordsize=4
--- ctx.spellcheck.wordpath=ENV(CTXSPELLPATH)
---
--- ctx.spellcheck.wordfile.all=spell-uk.txt,spell-nl.txt
---
--- ctx.spellcheck.wordfile.uk=spell-uk.txt
--- ctx.spellcheck.wordfile.nl=spell-nl.txt
--- ctx.spellcheck.wordsize.uk=4
--- ctx.spellcheck.wordsize.nl=4
---
--- command.name.21.*=CTX Action List
--- command.subsystem.21.*=3
--- command.21.*=show_menu $(ctx.menulist.default)
--- command.groupundo.21.*=yes
--- command.shortcut.21.*=Shift+F11
---
--- command.name.22.*=CTX Check Text
--- command.subsystem.22.*=3
--- command.22.*=check_text
--- command.groupundo.22.*=yes
--- command.shortcut.22.*=Ctrl+L
---
--- command.name.23.*=CTX Wrap Text
--- command.subsystem.23.*=3
--- command.23.*=wrap_text
--- command.groupundo.23.*=yes
--- command.shortcut.23.*=Ctrl+M
---
--- # command.21.*=check_text
--- # command.21.*=dofile e:\context\lua\scite-ctx.lua
-
--- generic functions
-
-local crlf = "\n"
-
-function traceln(str)
- trace(str .. crlf)
- io.flush()
-end
-
-table.len = table.getn
-table.join = table.concat
-
-function table.found(tab, str)
- local l, r, p
- if string.len(str) == 0 then
- return false
- else
- l, r = 1, table.len(tab)
- while l <= r do
- p = math.floor((l+r)/2)
- if str < tab[p] then
- r = p - 1
- elseif str > tab[p] then
- l = p + 1
- else
- return true
- end
- end
- return false
- end
-end
-
-function string.grab(str, delimiter)
- local list = {}
- for snippet in string.gfind(str,delimiter) do
- table.insert(list, snippet)
- end
- return list
-end
-
-function string.join(list, delimiter)
- local size, str = table.len(list), ''
- if size > 0 then
- str = list[1]
- for i = 2, size, 1 do
- str = str .. delimiter .. list[i]
- end
- end
- return str
-end
-
-function string.spacy(str)
- if string.find(str,"^%s*$") then
- return true
- else
- return false
- end
-end
-
-function string.alphacmp(a,b,i) -- slow but ok
- if i and i > 0 then
- return string.lower(string.gsub(string.sub(a,i),'0',' ')) < string.lower(string.gsub(string.sub(b,i),'0',' '))
- else
- return string.lower(a) < string.lower(b)
- end
-end
-
-function table.alphasort(list,i)
- table.sort(list, function(a,b) return string.alphacmp(a,b,i) end)
-end
-
-function io.exists(filename)
- local ok, result, message = pcall(io.open,filename)
- if result then
- io.close(result)
- return true
- else
- return false
- end
-end
-
-function os.envvar(str)
- if os.getenv(str) ~= '' then
- return os.getenv(str)
- elseif os.getenv(string.upper(str)) ~= '' then
- return os.getenv(string.upper(str))
- elseif os.getenv(string.lower(str)) ~= '' then
- return os.getenv(string.lower(str))
- else
- return ''
- end
-end
-
-function string.expand(str)
- return string.gsub(str, "ENV%((%w+)%)", os.envvar)
-end
-
-function string.strip(str)
- return string.gsub(string.gsub(str,"^%s+",''),"%s+$",'')
-end
-
-function string.replace(original,pattern,replacement)
- local str = string.gsub(original,pattern,replacement)
--- print(str) -- indirect, since else str + nofsubs
- return str -- indirect, since else str + nofsubs
-end
-
--- support functions, maybe editor namespace
-
--- function column_of_position(position)
--- local line = editor:LineFromPosition(position)
--- local oldposition = editor.CurrentPos
--- local column = 0
--- editor:GotoPos(position)
--- while editor.CurrentPos ~= 0 and line == editor:LineFromPosition(editor.CurrentPos) do
--- editor:CharLeft()
--- column = column + 1
--- end
--- editor:GotoPos(oldposition)
--- if line > 0 then
--- return column -1
--- else
--- return column
--- end
--- end
-
--- function line_of_position(position)
--- return editor:LineFromPosition(position)
--- end
-
-function extend_to_start()
- local selectionstart = editor.SelectionStart
- local selectionend = editor.SelectionEnd
- local line = editor:LineFromPosition(selectionstart)
- if line > 0 then
- while line == editor:LineFromPosition(selectionstart-1) do
- selectionstart = selectionstart - 1
- editor:SetSel(selectionstart,selectionend)
- end
- else
- selectionstart = 0
- end
- editor:SetSel(selectionstart,selectionend)
- return selectionstart
-end
-
-function extend_to_end() -- editor:LineEndExtend() does not work
- local selectionstart = editor.SelectionStart
- local selectionend = editor.SelectionEnd
- local line = editor:LineFromPosition(selectionend)
- while line == editor:LineFromPosition(selectionend+1) do
- selectionend = selectionend + 1
- editor:SetSel(selectionstart,selectionend)
- end
- editor:SetSel(selectionstart,selectionend)
- return selectionend
-end
-
-function getfiletype()
- local firstline = editor:GetLine(0)
- if editor.Lexer == SCLEX_TEX then
- return 'tex'
- elseif editor.Lexer == SCLEX_XML then
- return 'xml'
- elseif string.find(firstline,"^%%") then
- return 'tex'
- elseif string.find(firstline,"^<%?xml") then
- return 'xml'
- else
- return 'unknown'
- end
-end
-
--- inspired by LuaExt's scite_Files
-
-function get_dir_list(mask)
- local f
- if props['PLAT_GTK'] and props['PLAT_GTK'] ~= "" then
- f = io.popen('ls -1 ' .. mask)
- else
- mask = string.gsub(mask, '/','\\')
- local tmpfile = 'scite-ctx.tmp'
- local cmd = 'dir /b "' .. mask .. '" > ' .. tmpfile
- os.execute(cmd)
- f = io.open(tmpfile)
- end
- local files = {}
- if not f then -- path check added
- return files
- end
- for line in f:lines() do
- table.insert(files, line)
- end
- f:close()
- return files
-end
-
--- banner
-
-print("loading scite-ctx.lua definition file")
-print("")
-print("- see scite-ctx.properties for configuring info")
-print("")
-print("- ctx.spellcheck.wordpath set to " .. props['ctx.spellcheck.wordpath'])
-if string.find(string.lower(props['ctx.spellcheck.wordpath']), "ctxspellpath") then
- if os.getenv('ctxspellpath') then
- print("- ctxspellpath set to " .. os.getenv('CTXSPELLPATH'))
- else
- print("- 'ctxspellpath is not set")
- end
- print("- ctx.spellcheck.wordpath expands to " .. string.expand(props['ctx.spellcheck.wordpath']))
-end
-print("")
-print("- ctx.wraptext.length is set to " .. props['ctx.wraptext.length'])
-if props['ctx.helpinfo'] ~= '' then
- print("- key bindings:")
- print("")
- print(string.replace(string.strip(props['ctx.helpinfo']),"%s*\|%s*","\n")) -- indirect, since else str + nofsubs
-end
-print("")
-print("- recognized first lines:")
-print("")
-print("xml <?xml version='1.0' language='nl'")
-print("tex % language=nl")
-
-
--- text functions
-
--- written while listening to Talk Talk
-
-local magicstring = string.rep("<ctx-crlf/>", 2)
-
-function wrap_text()
-
- -- We always go to the end of a line, so in fact some of
- -- the variables set next are not needed.
-
- local length = props["ctx.wraptext.length"]
-
- if length == '' then length = 80 else length = tonumber(length) end
-
- local startposition = editor.SelectionStart
- local endposition = editor.SelectionEnd
-
- if startposition == endposition then return end
-
- editor:LineEndExtend()
-
- startposition = editor.SelectionStart
- endposition = editor.SelectionEnd
-
- -- local startline = line_of_position(startposition)
- -- local endline = line_of_position(endposition)
- -- local startcolumn = column_of_position(startposition)
- -- local endcolumn = column_of_position(endposition)
- --
- -- editor:SetSel(startposition,endposition)
-
- local startline = props['SelectionStartLine']
- local endline = props['SelectionEndLine']
- local startcolumn = props['SelectionStartColumn'] - 1
- local endcolumn = props['SelectionEndColumn'] - 1
-
- local indentation = string.rep(' ', startcolumn)
- local selection = string.gsub(editor:GetSelText(),"[\n\r][\n\r]", "\n")
- local selection = string.gsub(selection,"\n\n+", ' ' .. magicstring .. ' ')
- local replacement = ''
- local templine = ''
-
- selection = string.gsub(selection,"^%s", '')
-
- for snippet in string.gfind(selection, "%S+") do
- if snippet == magicstring then
- replacement = replacement .. templine .. "\n\n"
- templine = ''
- elseif string.len(templine) + string.len(snippet) > length then
- replacement = replacement .. templine .. "\n"
- templine = indentation .. snippet
- elseif string.len(templine) == 0 then
- templine = indentation .. snippet
- else
- templine = string.len(templine) .. ' ' .. snippet
- end
- end
-
- replacement = replacement .. templine
- replacement = string.gsub(replacement, "^%s+", '')
-
- if endcolumn == 0 then
- replacement = replacement .. "\n"
- end
-
- editor:ReplaceSel(replacement)
-
-end
-
-function unwrap_text()
-
- local startposition = editor.SelectionStart
- local endposition = editor.SelectionEnd
-
- if startposition == endposition then return end
-
- editor:HomeExtend()
- editor:LineEndExtend()
-
- startposition = editor.SelectionStart
- endposition = editor.SelectionEnd
-
- local magicstring = string.rep("<multiplelines/>", 2)
- local selection = string.gsub(editor:GetSelText(),"[\n\r][\n\r]+", ' ' .. magicstring .. ' ')
- local replacement = ''
-
- for snippet in string.gfind(selection, "%S+") do
- if snippet == magicstring then
- replacement = replacement .. "\n"
- else
- replacement = replacement .. snippet .. "\n"
- end
- end
-
- if endcolumn == 0 then replacement = replacement .. "\n" end
-
- editor:ReplaceSel(replacement)
-
-end
-
-function sort_text()
-
- local startposition = editor.SelectionStart
- local endposition = editor.SelectionEnd
-
- if startposition == endposition then return end
-
- -- local startcolumn = column_of_position(startposition)
- -- local endcolumn = column_of_position(endposition)
- --
- -- editor:SetSel(startposition,endposition)
-
- local startline = props['SelectionStartLine']
- local endline = props['SelectionEndLine']
- local startcolumn = props['SelectionStartColumn'] - 1
- local endcolumn = props['SelectionEndColumn'] - 1
-
- startposition = extend_to_start()
- endposition = extend_to_end()
-
- local selection = string.gsub(editor:GetSelText(), "%s*$", '')
-
- list = string.grab(selection,"[^\n\r]+")
- table.alphasort(list, startcolumn)
- local replacement = table.concat(list, "\n")
-
- editor:GotoPos(startposition)
- editor:SetSel(startposition,endposition)
-
- if endcolumn == 0 then replacement = replacement .. "\n" end
-
- editor:ReplaceSel(replacement)
-
-end
-
-function document_text()
-
- local startposition = editor.SelectionStart
- local endposition = editor.SelectionEnd
-
- if startposition == endposition then return end
-
- startposition = extend_to_start()
- endposition = extend_to_end()
-
- editor:SetSel(startposition,endposition)
-
- local filetype = getfiletype()
-
- local replacement = ''
- for i = editor:LineFromPosition(startposition), editor:LineFromPosition(endposition) do
- local str = editor:GetLine(i)
- if filetype == 'xml' then
- if string.find(str,"^<%!%-%- .* %-%->%s*$") then
- replacement = replacement .. string.gsub(str,"^<%!%-%- (.*) %-%->(%s*)$", "%1\n")
- elseif not string.spacy(str) then
- replacement = replacement .. '<!-- ' .. string.gsub(str,"(%s*)$", '') .. " -->\n"
- else
- replacement = replacement .. str
- end
- else
- if string.find(str,"^%%D%s+$") then
- replacement = replacement .. "\n"
- elseif string.find(str,"^%%D ") then
- replacement = replacement .. string.gsub(str,"^%%D ", '')
- else
- replacement = replacement .. '%D ' .. str
- end
- end
- end
-
- editor:ReplaceSel(string.gsub(replacement, "[\n\r]$", ''))
-
-end
-
-function quote_text()
-
- local filetype, leftquotation, rightquotation = getfiletype(), '', ''
-
- if filetype == 'xml' then
- leftquotation, rightquotation = "<quotation>", "</quotation>"
- leftquote, rightquote = "<quotation>", "</quote>"
- else
- leftquotation, rightquotation = "\\quotation {", "}"
- leftquote, rightquote = "\\quote {", "}"
- end
-
- local replacement = editor:GetSelText()
- replacement = string.gsub(replacement, "\`\`(.-)\'\'", leftquotation .. "%1" .. rightquotation)
- replacement = string.gsub(replacement, "\"(.-)\"", leftquotation .. "%1" .. rightquotation)
- replacement = string.gsub(replacement, "\`(.-)\'", leftquote .. "%1" .. rightquote )
- replacement = string.gsub(replacement, "\'(.-)\'", leftquote .. "%1" .. rightquote )
- editor:ReplaceSel(replacement)
-
-end
-
-function compound_text()
-
- local filetype = getfiletype()
-
- if filetype == 'xml' then
- editor:ReplaceSel(string.gsub(editor:GetSelText(),"(>[^<%-][^<%-]+)([-\/])(%w%w+)","%1<compound token='%2'/>%3"))
- else
- editor:ReplaceSel(string.gsub(editor:GetSelText(),"([^\|])([-\/]+)([^\|])","%1|%2|%3"))
- end
-
-end
-
--- written while listening to Alanis Morissette's acoustic
--- Jagged Little Pill and Tori Amos' Beekeeper after
--- reinstalling on my good old ATH-7
-
-local language = props["ctx.spellcheck.language"]
-local wordsize = props["ctx.spellcheck.wordsize"]
-local wordpath = props["ctx.spellcheck.wordpath"]
-
-if language == '' then language = 'uk' end
-if wordsize == '' then wordsize = 4 else wordsize = tonumber(wordsize) end
-
-local wordfile = ""
-local wordlist = {}
-local worddone = 0
-
--- we use wordlist as a hash so that we can add entries without the
--- need to sort and also use a fast (built in) search
-
--- function kpsewhich_file(filename,filetype,progname)
--- local progflag, typeflag = '', ''
--- local tempname = os.tmpname()
--- if progname then
--- progflag = " --progname=" .. progname .. " "
--- end
--- if filetype then
--- typeflag = " --format=" .. filetype .. " "
--- end
--- local command = "kpsewhich" .. progflag .. typeflag .. " " .. filename .. " > " .. tempname
--- os.execute(command)
--- for line in io.lines(tempname) do
--- return string.gsub(line, "\s*$", '')
--- end
--- end
-
-function check_text()
-
- local dlanguage = props["ctx.spellcheck.language"]
- local dwordsize = props["ctx.spellcheck.wordsize"]
- local dwordpath = props["ctx.spellcheck.wordpath"]
-
- if dlanguage ~= '' then dlanguage = tostring(language) end
- if dwordsize ~= '' then dwordsize = tonumber(wordsize) end
-
- local firstline, skipfirst = editor:GetLine(0), false
- local filetype, wordskip, wordgood = getfiletype(), '', ''
-
- if filetype == 'tex' then
- wordskip = "\\"
- elseif filetype == 'xml' then
- wordskip = "<"
- wordgood = ">"
- end
-
- if props["ctx.spellcheck.language"] == 'auto' then
- if filetype == 'tex' then
- -- % version =1.0 language=uk
- firstline = string.gsub(firstline, "^%%%s*", '')
- firstline = string.gsub(firstline, "%s*$", '')
- for key, val in string.gfind(firstline,"(%w+)=(%w+)") do
- if key == "language" then
- language = val
- traceln("auto document language " .. "'" .. language .. "' (tex)")
- end
- end
- skipfirst = true
- elseif filetype == 'xml' then
- -- <?xml version='1.0' language='uk' ?>
- firstline = string.gsub(firstline, "^%<%?xml%s*", '')
- firstline = string.gsub(firstline, "%s*%?%>%s*$", '')
- for key, val in string.gfind(firstline,"(%w+)=[\"\'](.-)[\"\']") do
- if key == "language" then
- language = val
- traceln("auto document language " .. "'" .. language .. "' (xml)")
- end
- end
- skipfirst = true
- end
- end
-
- local fname = props["ctx.spellcheck.wordfile." .. language]
- local fsize = props["ctx.spellcheck.wordsize." .. language]
-
- if fsize ~= '' then wordsize = tonumber(fsize) end
-
- if fname ~= '' and fname ~= wordfile then
- wordfile, worddone, wordlist = fname, 0, {}
- for filename in string.gfind(wordfile,"[^%,]+") do
- if wordpath ~= '' then
- filename = string.expand(wordpath) .. '/' .. filename
- end
- if io.exists(filename) then
- traceln("loading " .. filename)
- for line in io.lines(filename) do
- if not string.find(line,"^[\%\#\-]") then
- str = string.gsub(line,"%s*$", '')
- rawset(wordlist,str,true) -- table.insert(wordlist,str)
- worddone = worddone + 1
- end
- end
- else
- traceln("unknown file '" .. filename .."'")
- end
- end
- traceln(worddone .. " words loaded")
- end
-
- reset_text()
-
- if worddone == 0 then
- traceln("no (valid) language or wordfile specified")
- else
- traceln("start checking")
- if wordskip ~= '' then
- traceln("ignoring " .. wordskip .. "..." .. wordgood)
- end
- local i, j, lastpos, startpos, endpos, snippet, len, first = 0, 0, -1, 0, 0, '', 0, 0
- local ok, skip, ch = false, false, ''
- if skipfirst then first = string.len(firstline) end
- for k = first, editor.TextLength do
- ch = editor:textrange(k,k+1)
- if wordgood ~= '' and ch == wordgood then
- skip = false
- elseif ch == wordskip then
- skip = true
- end
- if string.find(ch,"%w") and not string.find(ch,"%d") then
- if not skip then
- if ok then
- endpos = k
- else
- startpos = k
- endpos = k
- ok = true
- end
- end
- elseif ok and not skip then
- len = endpos - startpos + 1
- if len >= wordsize then
- snippet = editor:textrange(startpos,endpos+1)
- i = i + 1
- if wordlist[snippet] or wordlist[string.lower(snippet)] then -- table.found(wordlist,snippet)
- j = j + 1
- else
- editor:StartStyling(startpos,INDICS_MASK)
- editor:SetStyling(len,INDIC2_MASK) -- INDIC0_MASK+2
- end
- end
- ok = false
- elseif wordgood == '' then
- skip = (ch == wordskip)
- end
- end
- traceln(i .. " words checked, " .. (i-j) .. " errors")
- end
-
-end
-
-function reset_text()
- editor:StartStyling(0,INDICS_MASK)
- editor:SetStyling(editor.TextLength,INDIC_PLAIN)
-end
-
--- menu
-
-local menuactions = {}
-local menufunctions = {}
-
-function UserListShow(menutrigger, menulist)
- local menuentries = {}
- local list = string.grab(menulist,"[^%|]+")
- menuactions = {}
- for i=1, table.len(list) do
- if list[i] ~= '' then
- for key, val in string.gfind(list[i],"%s*(.+)=(.+)%s*") do
- table.insert(menuentries,key)
- rawset(menuactions,key,val)
- end
- end
- end
- local menustring = table.join(menuentries,'|')
- if menustring == "" then
- traceln("There are no templates defined for this file type.")
- else
- editor.AutoCSeparator = string.byte('|')
- editor:UserListShow(menutrigger,menustring)
- editor.AutoCSeparator = string.byte(' ')
- end
-end
-
-function OnUserListSelection(trigger,choice)
- if menufunctions[trigger] and menuactions[choice] then
- return menufunctions[trigger](menuactions[choice])
- else
- return false
- end
-end
-
--- main menu
-
-local menutrigger = 12
-
-function show_menu(menulist)
- UserListShow(menutrigger, menulist)
-end
-
-function process_menu(action)
- if not string.find(action,"%(%)$") then
- assert(loadstring(action .. "()"))()
- else
- assert(loadstring(action))()
- end
-end
-
-menufunctions[12] = process_menu
-
--- templates
-
-local templatetrigger = 13
-
--- local ctx_template_paths = { "./ctx-templates", "../ctx-templates", "../../ctx-templates" }
--- local ctx_auto_templates = false
--- local ctx_template_list = ""
--- local ctx_dir_list = { }
--- local ctx_dir_name = "./ctx-templates"
-
--- local ctx_path_list = {}
--- local ctx_path_done = {}
-
--- function ctx_list_loaded()
--- return ctx_dir_list and table.getn(ctx_dir_list) > 0
--- end
-
--- function insert_template(templatelist)
--- if props["ctx.template.scan"] == "yes" then
--- local current = props["FileDir"] .. "+" .. props["FileExt"] -- no name
--- local rescan = props["ctx.template.rescan"] == "yes"
--- local suffix = props["ctx.template.suffix."..props["FileExt"]] -- alas, no suffix expansion here
--- if rescan then
--- print("re-scanning enabled")
--- end
--- if current ~= ctx_file_path then
--- rescan = true
--- ctx_file_path = current
--- ctx_file_done = false
--- ctx_template_list = ""
--- end
--- if not ctx_file_done or rescan then
--- local pattern = "*.*"
--- for i, pathname in ipairs(ctx_template_paths) do
--- print("scanning " .. pathname .. " for " .. pattern)
--- ctx_dir_name = pathname
--- ctx_dir_list = get_dir_list(pathname .. "/" .. pattern)
--- if ctx_list_loaded() then
--- break
--- end
--- end
--- ctx_file_done = true
--- end
--- if ctx_list_loaded() then
--- ctx_template_list = ""
--- local pattern = "%." .. suffix .. "$"
--- for j, filename in ipairs(ctx_dir_list) do
--- if string.find(filename,pattern) then
--- local menuname = string.gsub(filename,"%..-$","")
--- if ctx_template_list ~= "" then
--- ctx_template_list = ctx_template_list .. "|"
--- end
--- ctx_template_list = ctx_template_list .. menuname .. "=" .. ctx_dir_name .. "/" .. filename
--- end
--- end
--- else
--- print("no template files found")
--- end
--- if ctx_template_list == "" then
--- ctx_auto_templates = false
--- print("no file related templates found")
--- else
--- ctx_auto_templates = true
--- templatelist = ctx_template_list
--- end
--- end
--- if templatelist ~= "" then
--- UserListShow(templatetrigger, templatelist)
--- end
--- end
-
-local ctx_template_paths = { "./ctx-templates", "../ctx-templates", "../../ctx-templates" }
-local ctx_auto_templates = false
-local ctx_template_list = ""
-
-local ctx_path_list = {}
-local ctx_path_done = {}
-local ctx_path_name = {}
-
-function ctx_list_loaded(path)
- return ctx_path_list[path] and table.getn(ctx_path_list[path]) > 0
-end
-
-function insert_template(templatelist)
- if props["ctx.template.scan"] == "yes" then
- local path = props["FileDir"]
- local rescan = props["ctx.template.rescan"] == "yes"
- local suffix = props["ctx.template.suffix." .. props["FileExt"]] -- alas, no suffix expansion here
- local current = path .. "+" .. props["FileExt"]
- if rescan then
- print("re-scanning enabled")
- end
- ctx_template_list = ""
- if not ctx_path_done[path] or rescan then
- local pattern = "*.*"
- for i, pathname in ipairs(ctx_template_paths) do
- print("scanning " .. string.gsub(path,"\\","/") .. "/" .. pathname)
- ctx_path_name[path] = pathname
- ctx_path_list[path] = get_dir_list(pathname .. "/" .. pattern)
- if ctx_list_loaded(path) then
- print("finished locating template files")
- break
- end
- end
- if ctx_list_loaded(path) then
- print(table.getn(ctx_path_list[path]) .. " template files found")
- else
- print("no template files found")
- end
- end
- if ctx_list_loaded(path) then
- ctx_template_list = ""
- local pattern = "%." .. suffix .. "$"
- local n = 0
- for j, filename in ipairs(ctx_path_list[path]) do
- if string.find(filename,pattern) then
- n = n + 1
- local menuname = string.gsub(filename,"%..-$","")
- if ctx_template_list ~= "" then
- ctx_template_list = ctx_template_list .. "|"
- end
- ctx_template_list = ctx_template_list .. menuname .. "=" .. ctx_path_name[path] .. "/" .. filename
- end
- end
- if not ctx_path_done[path] then
- print(n .. " suitable template files found")
- end
- end
- ctx_path_done[path] = true
- if ctx_template_list == "" then
- ctx_auto_templates = false
- else
- ctx_auto_templates = true
- templatelist = ctx_template_list
- end
- else
- ctx_auto_templates = false
- end
- if templatelist ~= "" then
- UserListShow(templatetrigger, templatelist)
- end
-end
-
-
--- ctx.template.[whatever].[filetype]
--- ctx.template.[whatever].data.[filetype]
--- ctx.template.[whatever].file.[filetype]
--- ctx.template.[whatever].list.[filetype]
-
-function process_template_one(action)
- local text = nil
- if ctx_auto_templates then
- local f = io.open(action,"r")
- if f then
- text = string.gsub(f:read("*all"),"\n$","")
- f:close()
- else
- print("unable to auto load template file " .. text)
- text = nil
- end
- end
- if not text or text == "" then
- text = props["ctx.template." .. action .. ".file"]
- if not text or text == "" then
- text = props["ctx.template." .. action .. ".data"]
- if not text or text == "" then
- text = props["ctx.template." .. action]
- end
- else
- local f = io.open(text,"r")
- if f then
- text = string.gsub(f:read("*all"),"\n$","")
- f:close()
- else
- print("unable to load template file " .. text)
- text = nil
- end
- end
- end
- if text then
- text = string.replace(text,"\\n","\n")
- local pos = string.find(text,"%?")
- text = string.replace(text,"%?","")
- editor:insert(editor.CurrentPos,text)
- if pos then
- editor.CurrentPos = editor.CurrentPos + pos - 1
- editor.SelectionStart = editor.CurrentPos
- editor.SelectionEnd = editor.CurrentPos
- editor:GotoPos(editor.CurrentPos)
- end
- end
-end
-
-menufunctions[13] = process_template_one
-menufunctions[14] = process_template_two
-
--- command.name.26.*=Open Logfile
--- command.subsystem.26.*=3
--- command.26.*=open_log
--- command.save.before.26.*=2
--- command.groupundo.26.*=yes
--- command.shortcut.26.*=Ctrl+E
-
-function open_log()
- scite.Open(props['FileName'] .. ".log")
-end
diff --git a/scripts/context/ruby/base/kpse.rb b/scripts/context/ruby/base/kpse.rb
index a4babae55..0e185b5b8 100644
--- a/scripts/context/ruby/base/kpse.rb
+++ b/scripts/context/ruby/base/kpse.rb
@@ -64,8 +64,12 @@ module Kpse
# @@distribution = 'miktex' if ENV['PATH'] =~ /miktex[\\\/]bin/o
- if ENV['PATH'] =~ /(.*?)miktex[\\\/]bin/i then
- @@distribution = 'miktex' unless $1 =~ /(texmf\-mswin[\/\\]bin|bin[\/\\]win32)/i
+ # if ENV['PATH'] =~ /(.*?)miktex[\\\/]bin/i then
+ # @@distribution = 'miktex' unless $1 =~ /(texmf\-mswin[\/\\]bin|bin[\/\\]win32)/i
+ # end
+
+ if @@mswindows && (ENV['PATH'] =~ /(.*?)miktex[\\\/]bin/i) then
+ @@distribution = 'miktex' unless $1 =~ /(texmf\-mswin[\/\\]bin|bin[\/\\]win32)/i
end
@@re_true = /yes|on|true|1/i
diff --git a/scripts/context/ruby/base/tex.rb b/scripts/context/ruby/base/tex.rb
index 73b382af9..54d5bc730 100644
--- a/scripts/context/ruby/base/tex.rb
+++ b/scripts/context/ruby/base/tex.rb
@@ -90,25 +90,7 @@ class TEX
@@luafiles = "luafiles.tmp"
@@luatarget = "lua/context"
- # we now drop pdfetex definitely
-
- # ENV['PATH'].split(File::PATH_SEPARATOR).each do |p|
- # if System.unix? then
- # pp, pe = "#{p}/pdftex" , "#{p}/pdfetex"
- # else
- # pp, pe = "#{p}/pdftex.exe", "#{p}/pdfetex.exe"
- # end
- # if FileTest.file?(pe) then # we assume no update
- # @@pdftex = 'pdfetex'
- # break
- # elsif FileTest.file?(pp) then # we assume an update
- # @@pdftex = 'pdftex'
- # break
- # end
- # end
-
- # ['etex','pdfetex','standard'] .each do |e| @@texengines[e] = @@pdftex end
- # ['tex','pdftex'] .each do |e| @@texengines[e] = 'pdftex' end
+ @@platformslash = if System.unix? then "\\\\" else "\\" end
['tex','etex','pdftex','pdfetex','standard'] .each do |e| @@texengines[e] = 'pdftex' end
['aleph','omega'] .each do |e| @@texengines[e] = 'aleph' end
@@ -120,6 +102,7 @@ class TEX
['pdfetex','pdftex','pdf','pdftex','standard'] .each do |b| @@backends[b] = 'pdftex' end
['dvipdfmx','dvipdfm','dpx','dpm'] .each do |b| @@backends[b] = 'dvipdfmx' end
['xetex','xtx'] .each do |b| @@backends[b] = 'xetex' end
+ ['aleph'] .each do |b| @@backends[b] = 'dvipdfmx' end
['dvips','ps','dvi'] .each do |b| @@backends[b] = 'dvips' end
['dvipsone'] .each do |b| @@backends[b] = 'dvipsone' end
['acrobat','adobe','distiller'] .each do |b| @@backends[b] = 'acrobat' end
@@ -164,11 +147,11 @@ class TEX
['plain','default','standard'] .each do |f| @@mpsmethods[f] = 'plain' end
['metafun'] .each do |f| @@mpsmethods[f] = 'metafun' end
- @@texmakestr['plain'] = "\\dump"
- @@mpsmakestr['plain'] = "\\dump"
+ @@texmakestr['plain'] = @@platformslash + "dump"
+ @@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] = "\\emergencyend" end
+ 'cont-fr','cont-cz','cont-ro','cont-uk'] .each do |f| @@texprocstr[f] = @@platformslash + "emergencyend" end
@@runoptions['aleph'] = ['--8bit']
@@runoptions['luatex'] = ['--file-line-error']
@@ -1885,7 +1868,7 @@ end
if globalfile || FileTest.file?(rawname) then
- if not dummyfile and not globalfile then
+ if not dummyfile and not globalfile and not forcexml then
scantexpreamble(rawname)
scantexcontent(rawname) if getvariable('texformats').standard?
end
diff --git a/scripts/context/ruby/base/texutil.rb b/scripts/context/ruby/base/texutil.rb
index 9c43f00e9..4882404d5 100644
--- a/scripts/context/ruby/base/texutil.rb
+++ b/scripts/context/ruby/base/texutil.rb
@@ -706,8 +706,8 @@ class TeXUtil
elsif alpha == @@specialsymbol then
character = @@specialbanner
elsif alpha.length > 1 then
- # character = "\\getvalue\{#{alpha}\}%"
- character = "\\#{alpha}%"
+ # character = "\\getvalue\{#{alpha}\}"
+ character = "\\#{alpha}"
else
character = "\\unknown"
end
diff --git a/scripts/context/ruby/graphics/gs.rb b/scripts/context/ruby/graphics/gs.rb
index a73400ba2..cb3d016f4 100644
--- a/scripts/context/ruby/graphics/gs.rb
+++ b/scripts/context/ruby/graphics/gs.rb
@@ -296,9 +296,9 @@ class GhostScript
def gscolorswitch
case getvariable('colormodel')
- when 'cmyk' then '-dProcessColorModel=/DeviceCMYK '
- when 'rgb' then '-dProcessColorModel=/DeviceRGB '
- when 'gray' then '-dProcessColorModel=/DeviceGRAY '
+ when 'cmyk' then '-dProcessColorModel=/DeviceCMYK -dColorConversionStrategy=/CMYK '
+ when 'rgb' then '-dProcessColorModel=/DeviceRGB -dColorConversionStrategy=/RGB '
+ when 'gray' then '-dProcessColorModel=/DeviceGRAY -dColorConversionStrategy=/GRAY '
else
''
end
diff --git a/scripts/context/ruby/texexec.rb b/scripts/context/ruby/texexec.rb
index 3ba3388f0..d2c722438 100644
--- a/scripts/context/ruby/texexec.rb
+++ b/scripts/context/ruby/texexec.rb
@@ -111,7 +111,7 @@ class Commands
if job = TEX.new(logger) then
prepare(job)
job.cleanuptemprunfiles
- files = @commandline.arguments.sort
+ files = if @commandline.option('sort') then @commandline.arguments.sort else @commandline.arguments end
if files.length > 0 then
if f = File.open(job.tempfilename('tex'),'w') then
backspace = @commandline.checkedoption('backspace', '1.5cm')
@@ -156,7 +156,7 @@ class Commands
prepare(job)
job.cleanuptemprunfiles
fast = @commandline.option('fast')
- files = @commandline.arguments.sort
+ files = if @commandline.option('sort') then @commandline.arguments.sort else @commandline.arguments end
if fast or (files.length > 0) then
if f = File.open(job.tempfilename('tex'),'w') then
files.delete("texexec.pdf")
@@ -202,7 +202,7 @@ class Commands
if job = TEX.new(logger) then
prepare(job)
job.cleanuptemprunfiles
- files = @commandline.arguments.sort
+ files = if @commandline.option('sort') then @commandline.arguments.sort else @commandline.arguments end
msuffixes = ['tex','mkii','mkiv','mp','pl','pm','rb']
if files.length > 0 then
files.each do |fname|
@@ -302,7 +302,7 @@ class Commands
if job = TEX.new(logger) then
prepare(job)
job.cleanuptemprunfiles
- files = @commandline.arguments.sort
+ files = if @commandline.option('sort') then @commandline.arguments.sort else @commandline.arguments end
if files.length > 0 then
if f = File.open(job.tempfilename('tex'),'w') then
emptypages = @commandline.checkedoption('addempty', '')
@@ -355,7 +355,7 @@ class Commands
if job = TEX.new(logger) then
prepare(job)
job.cleanuptemprunfiles
- files = @commandline.arguments.sort
+ files = if @commandline.option('sort') then @commandline.arguments.sort else @commandline.arguments end
if files.length > 0 then
if f = File.open(job.tempfilename('tex'),'w') then
selection = @commandline.checkedoption('selection', '')
@@ -425,7 +425,7 @@ class Commands
if job = TEX.new(logger) then
prepare(job)
job.cleanuptemprunfiles
- files = @commandline.arguments.sort
+ files = if @commandline.option('sort') then @commandline.arguments.sort else @commandline.arguments end
if files.length > 0 then
if f = File.open(job.tempfilename('tex'),'w') then
scale = @commandline.checkedoption('scale')
@@ -492,7 +492,7 @@ class Commands
if job = TEX.new(logger) then
prepare(job)
job.cleanuptemprunfiles
- files = @commandline.arguments.sort
+ files = if @commandline.option('sort') then @commandline.arguments.sort else @commandline.arguments end
if files.length > 0 then
if f = File.open(job.tempfilename('tex'),'w') then
paperoffset = @commandline.checkedoption('paperoffset', '0cm')
@@ -762,6 +762,7 @@ commandline.registerflag('aleph')
commandline.registerflag('all')
commandline.registerflag('fast')
+commandline.registerflag('sort')
# generic
diff --git a/scripts/context/ruby/www/exa.rb b/scripts/context/ruby/www/exa.rb
index 997eab67d..20a40fc7b 100644
--- a/scripts/context/ruby/www/exa.rb
+++ b/scripts/context/ruby/www/exa.rb
@@ -368,6 +368,7 @@ class WWW
end
def handle_exastatus
+ get_cfg() # weird, needed for apache, but not for wwwserver
if request_variable('id').empty? then
if id = valid_session() then
send_result()
diff --git a/scripts/context/ruby/www/lib.rb b/scripts/context/ruby/www/lib.rb
index f5f362b12..b9a44c9f6 100644
--- a/scripts/context/ruby/www/lib.rb
+++ b/scripts/context/ruby/www/lib.rb
@@ -163,7 +163,7 @@ class WWW
@interface.set('template:login' , 'exalogin.htm')
@interface.set('process:timeout' , @@session_max_age)
@interface.set('process:threshold' , @@send_threshold)
- @interface.set('process:background', 'yes') # this demands a watchdog being active
+ @interface.set('process:background', 'yes') # this demands a watchdog being active
@interface.set('process:indirect' , 'no') # indirect download, no direct feed
@interface.set('process:autologin' , 'yes') # provide default interface when applicable
@interface.set('process:exaurl' , '') # this one will be used as replacement in templates
@@ -1226,6 +1226,12 @@ class WWW
return ! (@session.nothing?('gui') && @session.nothing?('path') && @session.nothing?('process'))
end
+ def get_cfg()
+ if data = load_interface_file() then
+ fetch_session_interface_variables(data)
+ end
+ end
+
end
class WWW