summaryrefslogtreecommitdiff
path: root/tex
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2009-10-16 16:13:00 +0200
committerHans Hagen <pragma@wxs.nl>2009-10-16 16:13:00 +0200
commit7f9b179ad5be5000f67192f283d20e7120402bd9 (patch)
tree18f83a8cbfe7fed1c2a6939fb4b2cf10473abbbe /tex
parentc878054f6360d50885dbdab96643a8f3ac61c46c (diff)
downloadcontext-7f9b179ad5be5000f67192f283d20e7120402bd9.tar.gz
beta 2009.10.16 16:13
Diffstat (limited to 'tex')
-rw-r--r--tex/context/base/anch-pos.lua7
-rw-r--r--tex/context/base/catc-ctx.tex16
-rw-r--r--tex/context/base/catc-def.tex12
-rw-r--r--tex/context/base/char-ini.mkiv3
-rw-r--r--tex/context/base/colo-ini.lua4
-rw-r--r--tex/context/base/cont-new.tex2
-rw-r--r--tex/context/base/context.mkii1
-rw-r--r--tex/context/base/context.mkiv3
-rw-r--r--tex/context/base/context.tex2
-rw-r--r--tex/context/base/core-ctx.lua7
-rw-r--r--tex/context/base/core-def.mkii12
-rw-r--r--tex/context/base/core-def.mkiv12
-rw-r--r--tex/context/base/core-job.lua7
-rw-r--r--tex/context/base/font-ctx.lua11
-rw-r--r--tex/context/base/font-ini.lua21
-rw-r--r--tex/context/base/font-ini.mkiv5
-rw-r--r--tex/context/base/font-mis.lua2
-rw-r--r--tex/context/base/font-otf.lua36
-rw-r--r--tex/context/base/font-otn.lua32
-rw-r--r--tex/context/base/font-tfm.lua1
-rw-r--r--tex/context/base/grph-inc.lua42
-rw-r--r--tex/context/base/grph-inc.mkii5
-rw-r--r--tex/context/base/l-aux.lua18
-rw-r--r--tex/context/base/l-file.lua4
-rw-r--r--tex/context/base/l-lpeg.lua12
-rw-r--r--tex/context/base/l-table.lua24
-rw-r--r--tex/context/base/l-xml.lua6
-rw-r--r--tex/context/base/luat-lib.mkiv8
-rw-r--r--tex/context/base/lxml-aux.lua428
-rw-r--r--tex/context/base/lxml-dir.lua107
-rw-r--r--tex/context/base/lxml-ent.lua109
-rw-r--r--tex/context/base/lxml-inf.lua53
-rw-r--r--tex/context/base/lxml-ini.lua1390
-rw-r--r--tex/context/base/lxml-ini.mkiv234
-rw-r--r--tex/context/base/lxml-lpt.lua1017
-rw-r--r--tex/context/base/lxml-mis.lua41
-rw-r--r--tex/context/base/lxml-pth.lua1735
-rw-r--r--tex/context/base/lxml-sor.lua6
-rw-r--r--tex/context/base/lxml-tab.lua762
-rw-r--r--tex/context/base/lxml-tex.lua1309
-rw-r--r--tex/context/base/lxml-xml.lua242
-rw-r--r--tex/context/base/math-vfu.lua5
-rw-r--r--tex/context/base/meta-pdf.lua4
-rw-r--r--tex/context/base/mult-sys.tex5
-rw-r--r--tex/context/base/node-bck.lua3
-rw-r--r--tex/context/base/node-fnt.lua1
-rw-r--r--tex/context/base/node-inj.lua9
-rw-r--r--tex/context/base/node-ref.lua21
-rw-r--r--tex/context/base/pack-rul.mkiv16
-rw-r--r--tex/context/base/page-lin.lua32
-rw-r--r--tex/context/base/page-lin.mkiv13
-rw-r--r--tex/context/base/scrp-ini.lua2
-rw-r--r--tex/context/base/sort-lan.mkii14
-rw-r--r--tex/context/base/spac-ver.lua15
-rw-r--r--tex/context/base/spac-ver.mkiv2
-rw-r--r--tex/context/base/strc-ini.lua4
-rw-r--r--tex/context/base/strc-ref.lua20
-rw-r--r--tex/context/base/strc-sec.mkiv2
-rw-r--r--tex/context/base/supp-fil.mkii2
-rw-r--r--tex/context/base/syst-aux.mkiv11
-rw-r--r--tex/context/base/syst-ext.mkii11
-rw-r--r--tex/context/base/syst-ltx.tex56
-rw-r--r--tex/context/base/x-ct.mkiv54
-rw-r--r--tex/context/base/x-ldx.tex2
-rw-r--r--tex/context/base/x-mathml.lua189
-rw-r--r--tex/context/base/x-mathml.mkiv37
-rw-r--r--tex/context/base/x-pending.mkiv1
-rw-r--r--tex/context/base/x-set-11.mkiv29
-rw-r--r--tex/context/bib/t-bib.mkii5
-rw-r--r--tex/context/bib/t-bib.mkiv62
-rw-r--r--tex/context/bib/t-bib.tex1929
-rw-r--r--tex/context/bib/t-bibltx.tex75
-rw-r--r--tex/context/interface/cont-cs.xml2
-rw-r--r--tex/context/interface/cont-de.xml2
-rw-r--r--tex/context/interface/cont-en.xml2
-rw-r--r--tex/context/interface/cont-fr.xml2
-rw-r--r--tex/context/interface/cont-it.xml2
-rw-r--r--tex/context/interface/cont-nl.xml2
-rw-r--r--tex/context/interface/cont-pe.xml2
-rw-r--r--tex/context/interface/cont-ro.xml2
-rw-r--r--tex/context/interface/t-bib.xml411
-rw-r--r--tex/generic/context/luatex-fonts-merged.lua142
82 files changed, 4445 insertions, 6503 deletions
diff --git a/tex/context/base/anch-pos.lua b/tex/context/base/anch-pos.lua
index 05498212f..61ed73933 100644
--- a/tex/context/base/anch-pos.lua
+++ b/tex/context/base/anch-pos.lua
@@ -80,12 +80,13 @@ function jobpositions.MPd(id) local jpi = pcol[id] or ptbs[id] texprint(ctxcatco
-- the following are only for MP so there we can leave out the pt
--- can be writes
+-- can be writes and no format needed any more
function jobpositions.MPxy(id)
local jpi = pcol[id] or ptbs[id]
if jpi then
texprint(ctxcatcodes,format('(%s-%s,%s-%s)',jpi[2],dx,jpi[3],dy))
+--~ texprint(ctxcatcodes,'(',jpi[2],'-',dx,',',jpi[3],'-',dy,')')
else
texprint(ctxcatcodes,'(0,0)')
end
@@ -94,6 +95,7 @@ function jobpositions.MPll(id)
local jpi = pcol[id] or ptbs[id]
if jpi then
texprint(ctxcatcodes,format('(%s-%s,%s-%s-%s)',jpi[2],dx,jpi[3],jpi[6],dy))
+--~ texprint(ctxcatcodes,'(',jpi[2],'-',dx,',',jpi[3],'-',jpi[6],'-',dy,')')
else
texprint(ctxcatcodes,'(0,0)')
end
@@ -102,6 +104,7 @@ function jobpositions.MPlr(id)
local jpi = pcol[id] or ptbs[id]
if jpi then
texprint(ctxcatcodes,format('(%s+%s-%s,%s-%s-%s)',jpi[2],jpi[4],dx,jpi[3],jpi[6],dy))
+--~ texprint(ctxcatcodes,'(',jpi[2],'+',jpi[4],'-',dx,',',jpi[3],'-',jpi[6],'-',dy,')')
else
texprint(ctxcatcodes,'(0,0)')
end
@@ -110,6 +113,7 @@ function jobpositions.MPur(id)
local jpi = pcol[id] or ptbs[id]
if jpi then
texprint(ctxcatcodes,format('(%s+%s-%s,%s+%s-%s)',jpi[2],jpi[4],dx,jpi[3],jpi[5],dy))
+--~ texprint(ctxcatcodes,'(',jpi[2],'+',jpi[4],'-',dx,',',jpi[3],'+',jpi[5],'-',dy,')')
else
texprint(ctxcatcodes,'(0,0)')
end
@@ -118,6 +122,7 @@ function jobpositions.MPul(id)
local jpi = pcol[id] or ptbs[id]
if jpi then
texprint(ctxcatcodes,format('(%s-%s,%s+%s-%s)',jpi[2],dx,jpi[3],jpi[5],dy))
+--~ texprint(ctxcatcodes,'(',jpi[2],'-',dx,',',jpi[3],'+',jpi[5],'-',dy,')')
else
texprint(ctxcatcodes,'(0,0)')
end
diff --git a/tex/context/base/catc-ctx.tex b/tex/context/base/catc-ctx.tex
index 83e802e77..21e7d0136 100644
--- a/tex/context/base/catc-ctx.tex
+++ b/tex/context/base/catc-ctx.tex
@@ -14,13 +14,13 @@
%D We prefer to define relevant catcode tables in this file instead
%D of everywhere around.
-\ifx\ctxcatcodes \undefined \newcatcodetable \ctxcatcodes \fi
-\ifx\mthcatcodes \undefined \newcatcodetable \mthcatcodes \fi % math, not used, too tricky
-\ifx\xmlcatcodesn\undefined \newcatcodetable \xmlcatcodesn \fi % normal
-\ifx\xmlcatcodese\undefined \newcatcodetable \xmlcatcodese \fi % entitle
-\ifx\xmlcatcodesr\undefined \newcatcodetable \xmlcatcodesr \fi % reduce
-\ifx\typcatcodesa\undefined \newcatcodetable \typcatcodesa \fi % { }
-\ifx\typcatcodesb\undefined \newcatcodetable \typcatcodesb \fi % < >
+\ifdefined \ctxcatcodes \else \newcatcodetable \ctxcatcodes \fi
+\ifdefined \mthcatcodes \else \newcatcodetable \mthcatcodes \fi % math, not used, too tricky
+\ifdefined \xmlcatcodesn \else \newcatcodetable \xmlcatcodesn \fi % normal
+\ifdefined \xmlcatcodese \else \newcatcodetable \xmlcatcodese \fi % entitle
+\ifdefined \xmlcatcodesr \else \newcatcodetable \xmlcatcodesr \fi % reduce
+\ifdefined \typcatcodesa \else \newcatcodetable \typcatcodesa \fi % { }
+\ifdefined \typcatcodesb \else \newcatcodetable \typcatcodesb \fi % < >
\startcatcodetable \ctxcatcodes
\catcode`\^^I = 10
@@ -202,7 +202,7 @@
\catcodetable \ctxcatcodes
\let\defaultcatcodetable\ctxcatcodes
-\let\xmlcatcodes \xmlcatcodesn
+\let\xmlcatcodes \xmlcatcodesn % beware, in mkiv we use \notcatcodes
\endinput
diff --git a/tex/context/base/catc-def.tex b/tex/context/base/catc-def.tex
index 0346f6dae..e80cfe125 100644
--- a/tex/context/base/catc-def.tex
+++ b/tex/context/base/catc-def.tex
@@ -13,12 +13,12 @@
%D The following catcode tables are rather \CONTEXT\ independent.
-\ifx\nilcatcodes \undefined \newcatcodetable \nilcatcodes \fi
-\ifx\texcatcodes \undefined \newcatcodetable \texcatcodes \fi
-\ifx\luacatcodes \undefined \newcatcodetable \luacatcodes \fi
-\ifx\notcatcodes \undefined \newcatcodetable \notcatcodes \fi
-\ifx\vrbcatcodes \undefined \newcatcodetable \vrbcatcodes \fi
-\ifx\prtcatcodes \undefined \newcatcodetable \prtcatcodes \fi
+\ifdefined\nilcatcodes \else \newcatcodetable \nilcatcodes \fi
+\ifdefined\texcatcodes \else \newcatcodetable \texcatcodes \fi
+\ifdefined\luacatcodes \else \newcatcodetable \luacatcodes \fi
+\ifdefined\notcatcodes \else \newcatcodetable \notcatcodes \fi
+\ifdefined\vrbcatcodes \else \newcatcodetable \vrbcatcodes \fi
+\ifdefined\prtcatcodes \else \newcatcodetable \prtcatcodes \fi
\startcatcodetable \nilcatcodes
\catcode`\^^I = 10 % ascii tab is a blank space
diff --git a/tex/context/base/char-ini.mkiv b/tex/context/base/char-ini.mkiv
index eb11fd83c..2f1fe23a1 100644
--- a/tex/context/base/char-ini.mkiv
+++ b/tex/context/base/char-ini.mkiv
@@ -67,9 +67,10 @@
\number\xmlcatcodesn,
\number\xmlcatcodese,
\number\xmlcatcodesr,
+ \number\xmlcatcodes,
}
)
- catcodes.register("xmlcatcodes",\number\xmlcatcodes)
+ catcodes.register("xmlcatcodes",\number\xmlcatcodes)
}
\protect \endinput
diff --git a/tex/context/base/colo-ini.lua b/tex/context/base/colo-ini.lua
index 256af4707..fc63d6b3a 100644
--- a/tex/context/base/colo-ini.lua
+++ b/tex/context/base/colo-ini.lua
@@ -23,6 +23,8 @@ local a_transparency = attributes.private('transparency')
local a_colorspace = attributes.private('colormodel')
local a_background = attributes.private('background')
+-- no format needed any more or maybe use low level commands (less tokenization)
+
local a_l_c_template = "\\setevalue{(ca:%s)}{%s}" ..
"\\setevalue{(cs:%s)}{\\dosetattribute{color}{%s}}"
local a_g_c_template = "\\setxvalue{(ca:%s)}{%s}" ..
@@ -350,7 +352,7 @@ function colors.formatgray(ca,separator)
return format("%0.3f",(cv and cv[2]) or 0)
end
-function colors.colorcomponents(ca)
+function colors.colorcomponents(ca) -- return list
local cv = colors.value(ca)
if cv then
local model = cv[1]
diff --git a/tex/context/base/cont-new.tex b/tex/context/base/cont-new.tex
index f32c851dc..012a9c552 100644
--- a/tex/context/base/cont-new.tex
+++ b/tex/context/base/cont-new.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2009.10.02 13:14}
+\newcontextversion{2009.10.16 16:13}
%D This file is loaded at runtime, thereby providing an
%D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/context.mkii b/tex/context/base/context.mkii
index bbc05ae50..d5284cd25 100644
--- a/tex/context/base/context.mkii
+++ b/tex/context/base/context.mkii
@@ -34,6 +34,7 @@
\loadmarkfile{syst-ext}
\loadmarkfile{syst-new}
\loadmarkfile{syst-con}
+\loadcorefile{syst-ltx}
\loadmarkfile{thrd-trg} % based on: David Carlisle
\loadmarkfile{syst-fnt}
diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv
index 378a00873..bd2bbe504 100644
--- a/tex/context/base/context.mkiv
+++ b/tex/context/base/context.mkiv
@@ -43,6 +43,7 @@
\loadmarkfile{syst-aux}
\loadmarkfile{syst-lua}
\loadmarkfile{syst-con}
+\loadcorefile{syst-ltx}
\loadmarkfile{syst-fnt}
\loadmarkfile{syst-str}
@@ -315,7 +316,7 @@
\loadmarkfile{bibl-bib}
\loadmarkfile{bibl-tra}
-\loadmarkfile{x-xtag} % at some point this will nto be preloaded
+\loadmarkfile{x-xtag} % at some point this will not be preloaded
\loadcorefile{meta-xml}
diff --git a/tex/context/base/context.tex b/tex/context/base/context.tex
index 8354ede04..3f87e7a12 100644
--- a/tex/context/base/context.tex
+++ b/tex/context/base/context.tex
@@ -20,7 +20,7 @@
%D your styles an modules.
\edef\contextformat {\jobname}
-\edef\contextversion{2009.10.02 13:14}
+\edef\contextversion{2009.10.16 16:13}
%D For those who want to use this:
diff --git a/tex/context/base/core-ctx.lua b/tex/context/base/core-ctx.lua
index 4dbff3663..f9920d4c4 100644
--- a/tex/context/base/core-ctx.lua
+++ b/tex/context/base/core-ctx.lua
@@ -25,13 +25,12 @@ function commands.loadctxpreplist()
commands.writestatus("systems","loading ctx log file (specified)") -- todo: m!systems
end
--~ end
- for r, d, k in xml.elements(x,"ctx:prepfile") do
- local dk = d[k]
- local name = xml.content(dk)
+ for e in xml.collected(x,"ctx:prepfile") do
+ local name = xml.content(e)
if islocal then
name = file.basename(name)
end
- local done = dk.at['done'] or 'no'
+ local done = e.at['done'] or 'no'
if trace_prepfiles then
commands.writestatus("systems","registering %s -> %s",done)
end
diff --git a/tex/context/base/core-def.mkii b/tex/context/base/core-def.mkii
index e51cd96d3..bcf8d6b9d 100644
--- a/tex/context/base/core-def.mkii
+++ b/tex/context/base/core-def.mkii
@@ -81,4 +81,16 @@
\ifx\writetolistfalse \undefined \else \appendtoks \writetolistfalse \to \everybeforeutilityread \fi
\ifx\notesenabledfalse \undefined \else \appendtoks \notesenabledfalse \to \everybeforeutilityread \fi
+\def\synctexwarning
+ {\ifdefined\synctex \ifnum\synctex=\zerocount \else
+ \writeline
+ \writestatus\m!systems{BEWARE: syntex functionality is enabled!}%
+ \writeline
+ \globallet\synctexwarning\relax
+ \fi \fi}
+
+\prependtoks \synctexwarning \to \everyjob
+\prependtoks \synctexwarning \to \everystarttext
+\appendtoks \synctexwarning \to \everystoptext
+
\protect \endinput
diff --git a/tex/context/base/core-def.mkiv b/tex/context/base/core-def.mkiv
index 0943a5cf9..d3d24acd7 100644
--- a/tex/context/base/core-def.mkiv
+++ b/tex/context/base/core-def.mkiv
@@ -78,4 +78,16 @@
\synchronizelocallinespecs
\to \everyswitchtobodyfont
+\def\synctexwarning
+ {\ifdefined\synctex \ifnum\synctex=\zerocount \else
+ \writeline
+ \writestatus\m!systems{BEWARE: syntex functionality is enabled!}%
+ \writeline
+ \globallet\synctexwarning\relax
+ \fi \fi}
+
+\prependtoks \synctexwarning \to \everyjob
+\prependtoks \synctexwarning \to \everystarttext
+\appendtoks \synctexwarning \to \everystoptext
+
\protect \endinput
diff --git a/tex/context/base/core-job.lua b/tex/context/base/core-job.lua
index af2c71551..8f5517df3 100644
--- a/tex/context/base/core-job.lua
+++ b/tex/context/base/core-job.lua
@@ -89,11 +89,10 @@ end
local function convertexamodes(str)
local x = xml.convert(str)
- for e, d, k in xml.elements(x,"exa:variable") do
- local dk = d[k]
- local label = dk.at and dk.at.label
+ for e in xml.collected(x,"exa:variable") do
+ local label = e.at and e.at.label
if label and label ~= "" then
- local data = xml.content(dk) or ""
+ local data = xml.content(e) or ""
local mode = label:match("^mode:(.+)$")
if mode then
texsprint(ctxcatcodes,format("\\enablemode[%s:%s]",mode,data))
diff --git a/tex/context/base/font-ctx.lua b/tex/context/base/font-ctx.lua
index 54e724dd0..de1422454 100644
--- a/tex/context/base/font-ctx.lua
+++ b/tex/context/base/font-ctx.lua
@@ -297,26 +297,25 @@ function define.command_1(str)
elseif name == "unknown" then
texsprint(ctxcatcodes,"\\fcglet\\somefontname\\defaultfontfile")
else
- texsprint(ctxcatcodes,format("\\fcxdef\\somefontname{%s}",name))
+ texsprint(ctxcatcodes,"\\fcxdef\\somefontname{",name,"}")
end
-- we can also use a count for the size
if size and size ~= "" then
local mode, size = sizepattern:match(size)
if size and mode then
count.scaledfontmode = mode
- texsprint(ctxcatcodes,format("\\def\\somefontsize{%s}",size))
+ texsprint(ctxcatcodes,"\\def\\somefontsize{",size,"}")
else
count.scaledfontmode = 0
- texsprint(ctxcatcodes,format("\\let\\somefontsize\\empty",size))
+ texsprint(ctxcatcodes,"\\let\\somefontsize\\empty")
end
elseif true then
-- so we don't need to check in tex
count.scaledfontmode = 2
---~ texsprint(ctxcatcodes,format("\\def\\somefontsize{*}",size))
- texsprint(ctxcatcodes,format("\\let\\somefontsize\\empty",size))
+ texsprint(ctxcatcodes,"\\let\\somefontsize\\empty")
else
count.scaledfontmode = 0
- texsprint(ctxcatcodes,format("\\let\\somefontsize\\empty",size))
+ texsprint(ctxcatcodes,"\\let\\somefontsize\\empty")
end
specification = define.makespecification(str,lookup,name,sub,method,detail,size)
end
diff --git a/tex/context/base/font-ini.lua b/tex/context/base/font-ini.lua
index 6bebf6a86..5feb512b0 100644
--- a/tex/context/base/font-ini.lua
+++ b/tex/context/base/font-ini.lua
@@ -11,6 +11,8 @@ if not modules then modules = { } end modules ['font-ini'] = {
--ldx]]--
local utf = unicode.utf8
+local format, serialize = string.format, table.serialize
+local write_nl = texio.write_nl
if not fontloader then fontloader = fontforge end
@@ -91,7 +93,24 @@ function fonts.show_char_data(n)
end
local chr = tfmdata.characters[n]
if chr then
- texio.write_nl(table.serialize(chr,string.format("U_%04X",n)))
+ write_nl(format("%s @ %s => U%04X => %s => ",tfmdata.fullname,tfmdata.size,n,utf.char(n)) .. serialize(chr,false))
+ end
+ end
+end
+
+function fonts.show_font_parameters()
+ local tfmdata = fonts.ids[font.current()]
+ if tfmdata then
+ local parameters, mathconstants = tfmdata.parameters, tfmdata.MathConstants
+ local hasparameters, hasmathconstants = parameters and next(parameters), mathconstants and next(mathconstants)
+ if hasparameters then
+ write_nl(format("%s @ %s => parameters => ",tfmdata.fullname,tfmdata.size) .. serialize(parameters,false))
+ end
+ if hasmathconstants then
+ write_nl(format("%s @ %s => math constants => ",tfmdata.fullname,tfmdata.size) .. serialize(mathconstants,false))
+ end
+ if not hasparameters and not hasmathconstants then
+ write_nl(format("%s @ %s => no parameters and/or mathconstants",tfmdata.fullname,tfmdata.size))
end
end
end
diff --git a/tex/context/base/font-ini.mkiv b/tex/context/base/font-ini.mkiv
index 8c797652b..16ca08160 100644
--- a/tex/context/base/font-ini.mkiv
+++ b/tex/context/base/font-ini.mkiv
@@ -4011,6 +4011,11 @@
% \fi\fi\fi\fi
% \endcsname}
+%D goodies:
+
+\def\showchardata#1{\ctxlua{fonts.show_char_data("#1")}}
+\def\showfontdata {\ctxlua{fonts.show_font_parameters()}}
+
\protect \endinput
% \startluacode
diff --git a/tex/context/base/font-mis.lua b/tex/context/base/font-mis.lua
index cc20b9711..a1b717217 100644
--- a/tex/context/base/font-mis.lua
+++ b/tex/context/base/font-mis.lua
@@ -11,7 +11,7 @@ local lower, strip = string.lower, string.strip
fonts.otf = fonts.otf or { }
-fonts.otf.version = fonts.otf.version or 2.628
+fonts.otf.version = fonts.otf.version or 2.631
fonts.otf.pack = true
fonts.otf.cache = containers.define("fonts", "otf", fonts.otf.version, true)
diff --git a/tex/context/base/font-otf.lua b/tex/context/base/font-otf.lua
index cf3384126..59aff301b 100644
--- a/tex/context/base/font-otf.lua
+++ b/tex/context/base/font-otf.lua
@@ -82,7 +82,7 @@ otf.features.default = otf.features.default or { }
otf.enhancers = otf.enhancers or { }
otf.glists = { "gsub", "gpos" }
-otf.version = 2.628 -- beware: also sync font-mis.lua
+otf.version = 2.631 -- beware: also sync font-mis.lua
otf.pack = true -- beware: also sync font-mis.lua
otf.syncspace = true
otf.notdef = false
@@ -202,6 +202,7 @@ local enhancers = {
"patch bugs",
"merge cid fonts", "prepare unicode", "cleanup ttf tables", "compact glyphs", "reverse coverage",
"cleanup aat", "enrich with features", "add some missing characters",
+--~ "reorganize mark classes",
"reorganize kerns", -- moved here
"flatten glyph lookups", "flatten anchor tables", "flatten feature tables",
"prepare luatex tables",
@@ -354,6 +355,22 @@ end
-- todo: normalize, design_size => designsize
+otf.enhancers["reorganize mark classes"] = function(data,filename)
+ if data.mark_classes then
+ local unicodes = data.luatex.unicodes
+ local reverse = { }
+ for name, class in next, data.mark_classes do
+ local t = { }
+ for s in gmatch(class,"[^ ]+") do
+ t[unicodes[s]] = true
+ end
+ reverse[name] = t
+ end
+ data.luatex.markclasses = reverse
+ data.mark_classes = nil
+ end
+end
+
otf.enhancers["prepare luatex tables"] = function(data,filename)
data.luatex = data.luatex or { }
local luatex = data.luatex
@@ -657,12 +674,21 @@ otf.enhancers["analyse subtables"] = function(data,filename)
end
local flags = gk.flags
if flags then
+--~ gk.flags = { -- forcing false packs nicer
+--~ (flags.ignorecombiningmarks and "mark") or false,
+--~ (flags.ignoreligatures and "ligature") or false,
+--~ (flags.ignorebaseglyphs and "base") or false,
+--~ flags.r2l or false,
+--~ }
gk.flags = { -- forcing false packs nicer
- (flags.ignorecombiningmarks and "mark") or false,
- (flags.ignoreligatures and "ligature") or false,
- (flags.ignorebaseglyphs and "base") or false,
- flags.r2l or false
+ ((flags.ignorecombiningmarks or flags.mark_class) and "mark") or false,
+ ( flags.ignoreligatures and "ligature") or false,
+ ( flags.ignorebaseglyphs and "base") or false,
+ flags.r2l or false,
}
+--~ if flags.mark_class then
+--~ gk.markclass = luatex.markclasses[flags.mark_class]
+--~ end
end
end
end
diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua
index 66e7f7a3f..14837d2e1 100644
--- a/tex/context/base/font-otn.lua
+++ b/tex/context/base/font-otn.lua
@@ -136,6 +136,7 @@ local trace_bugs = false trackers.register("otf.bugs", function
local trace_details = false trackers.register("otf.details", function(v) trace_details = v end)
local trace_applied = false trackers.register("otf.applied", function(v) trace_applied = v end)
local trace_steps = false trackers.register("otf.steps", function(v) trace_steps = v end)
+local trace_skips = false trackers.register("otf.skips", function(v) trace_skips = v end)
trackers.register("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end)
trackers.register("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end)
@@ -1506,16 +1507,26 @@ end
-- we don't need to pass the currentcontext, saves a bit
-- make a slow variant then can be activated but with more tracing
+local function show_skip(kind,chainname,char,ck,class)
+ if ck[9] then
+ logwarning("%s: skipping char %s (%s) in rule %s, lookuptype %s (%s=>%s)",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10])
+ else
+ logwarning("%s: skipping char %s (%s) in rule %s, lookuptype %s",cref(kind,chainname),gref(char),class,ck[1],ck[2])
+ end
+end
+
local function normal_handle_contextchain(start,kind,chainname,contexts,sequence,cache)
-- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6]
local flags, done = sequence.flags, false
local skipmark, skipligature, skipbase = flags[1], flags[2], flags[3]
local someskip = skipmark or skipligature or skipbase -- could be stored in flags for a fast test (hm, flags could be false !)
+ local markclass = sequence.markclass
for k=1,#contexts do
local match, current, last = true, start, start
local ck = contexts[k]
local sequence = ck[3]
local s = #sequence
+ -- f..l = mid string
if s == 1 then
-- never happens
match = current.id == glyph and current.subtype<256 and current.font == currentfont and sequence[1][current.char]
@@ -1543,9 +1554,13 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
local ccd = descriptions[char]
if ccd then
local class = ccd.class
+--~ if class == skipmark or class == skipligature or class == skipbase or (markclass and not markclass[char]) then
if class == skipmark or class == skipligature or class == skipbase then
---~ if someskip and class == skipmark or class == skipligature or class == skipbase then
+--~ if someskip and (class == skipmark or class == skipligature or class == skipbase) then
-- skip 'm
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
last = last.next
elseif sequence[n][char] then
if n < l then
@@ -1573,6 +1588,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
-- end
end
if match and f > 1 then
+ -- before
local prev = start.prev
if prev then
local n = f-1
@@ -1585,9 +1601,13 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
local ccd = descriptions[char]
if ccd then
local class = ccd.class
+--~ if class == skipmark or class == skipligature or class == skipbase or (markclass and not markclass[char]) then
if class == skipmark or class == skipligature or class == skipbase then
--~ if someskip and class == skipmark or class == skipligature or class == skipbase then
-- skip 'm
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
elseif sequence[n][char] then
n = n -1
else
@@ -1624,9 +1644,10 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
end
end
if match and s > l then
+ -- after
local current = last.next
if current then
- -- removed optimiziation for s-l == 1, we have to deal with marks anyway
+ -- removed optimization for s-l == 1, we have to deal with marks anyway
local n = l + 1
while n <= s do
if current then
@@ -1637,9 +1658,13 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
local ccd = descriptions[char]
if ccd then
local class = ccd.class
+--~ if class == skipmark or class == skipligature or class == skipbase or (markclass and not markclass[char]) then
if class == skipmark or class == skipligature or class == skipbase then
--~ if someskip and class == skipmark or class == skipligature or class == skipbase then
-- skip 'm
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
elseif sequence[n][char] then
n = n + 1
else
@@ -1800,6 +1825,8 @@ end
local resolved = { } -- we only resolve a font,script,language pair once
+-- todo: pass all these 'locals' in a table
+
function fonts.methods.node.otf.features(head,font,attr)
if trace_steps then
checkstep(head)
@@ -1959,6 +1986,7 @@ function fonts.methods.node.otf.features(head,font,attr)
-- sequence kan weg
local ok
start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,1)
+--~ texio.write_nl(tostring(lookupname),tostring(lookupmatch),tostring(ok))
if ok then
success = true
end
diff --git a/tex/context/base/font-tfm.lua b/tex/context/base/font-tfm.lua
index aeaf4fc94..905da59ce 100644
--- a/tex/context/base/font-tfm.lua
+++ b/tex/context/base/font-tfm.lua
@@ -258,6 +258,7 @@ function tfm.do_scale(tfmtable, scaledpoints)
t.unicodes = tfmtable.unicodes
t.indices = tfmtable.indices
t.marks = tfmtable.marks
+t.colorscheme = tfmtable.colorscheme
t.descriptions = descriptions
if tfmtable.fonts then
t.fonts = table.fastcopy(tfmtable.fonts) -- hm also at the end
diff --git a/tex/context/base/grph-inc.lua b/tex/context/base/grph-inc.lua
index df60b87ba..57ac0bda4 100644
--- a/tex/context/base/grph-inc.lua
+++ b/tex/context/base/grph-inc.lua
@@ -190,8 +190,8 @@ function figures.setpaths(locationset,pathlist)
end
figures.paths, last_pathlist = t, pathlist
if trace_figures then
- logs.report("figures","locations: %s",last_locationset)
- logs.report("figures","path list: %s",table.concat(figures.paths))
+ commands.writestatus("figures","locations: %s",last_locationset)
+ commands.writestatus("figures","path list: %s",table.concat(figures.paths, " "))
end
end
@@ -300,7 +300,6 @@ do
end
end
function figures.tprint(category,tag,default)
---~ print("!!!!!!!!",category,tag,default)
texsprint(ctxcatcodes,figures.get(category,tag,default))
end
function figures.current()
@@ -355,15 +354,15 @@ local function register(askedname,specification)
if not found then
specification.found = false
if trace_figures then
- logs.report("figures","format not supported: %s",format)
+ commands.writestatus("figures","format not supported: %s",format)
end
else
specification.found = true
if trace_figures then
if validtypes[format] then
- logs.report("figures","format natively supported by backend: %s",format)
+ commands.writestatus("figures","format natively supported by backend: %s",format)
else
- logs.report("figures","format supported by output file format: %s",format)
+ commands.writestatus("figures","format supported by output file format: %s",format)
end
end
end
@@ -380,7 +379,7 @@ local function locate(request) -- name, format, cache
if figures.found[askedname] then
return figures.found[askedname]
end
- local askedpath= file.dirname(askedname)
+ local askedpath= file.is_rootbased_path(askedname)
local askedbase = file.basename(askedname)
local askedformat = (request.format ~= "" and request.format ~= "unknown" and request.format) or file.extname(askedname) or ""
local askedcache = request.cache
@@ -407,7 +406,7 @@ local function locate(request) -- name, format, cache
})
end
end
- if askedpath ~= "" then
+ if askedpath then
-- path and type given, todo: strip pieces of path
if figures.exists(askedname,askedformat) then
return register(askedname, {
@@ -442,7 +441,7 @@ local function locate(request) -- name, format, cache
end
end
end
- elseif askedpath ~= "" then
+ elseif askedpath then
for _, format in ipairs(figures.order) do
local list = figures.formats[format].list or { format }
for _, suffix in ipairs(list) do
@@ -592,17 +591,20 @@ end
-- -- -- generic -- -- --
-function figures.existers.generic(askedname)
---~ local result = io.exists(askedname)
---~ result = (result==true and askedname) or result
---~ local result = resolvers.find_file(askedname) or ""
- local result = resolvers.findbinfile(askedname) or ""
- if result == "" then result = false end
+function figures.existers.generic(askedname,resolve)
+ -- not findbinfile
+ local result
+ if lfs.isfile(askedname) then
+ result = askedname
+ elseif resolve then
+ result = resolvers.findbinfile(askedname) or ""
+ if result == "" then result = false end
+ end
if trace_figures then
if result then
- logs.report("figures","found: %s -> %s",askedname,result)
+ commands.writestatus("figures","found: %s -> %s",askedname,result)
else
- logs.report("figures","not found: %s",askedname)
+ commands.writestatus("figures","not found: %s",askedname)
end
end
return result
@@ -821,13 +823,13 @@ function bases.find(basename,askedlabel)
end
t = false
if base[2] and base[3] then -- rlx:library
- for e, d, k in xml.elements(base[3],"/(*:library|figurelibrary)/*:figure/*:label") do
+ for e in xml.collected(base[3],"/(*:library|figurelibrary)/*:figure/*:label") do
page = page + 1
- if xml.content(d[k]) == askedlabel then
+ if xml.content(e) == askedlabel then
t = {
base = file.replacesuffix(base[2],"pdf"),
format = "pdf",
- name = xml.filters.text(e,"*:file"),
+ name = xml.text(e,"../*:file"), -- to be checked
page = page,
}
bases.found[askedlabel] = t
diff --git a/tex/context/base/grph-inc.mkii b/tex/context/base/grph-inc.mkii
index dde7ab2e6..1bd7544d8 100644
--- a/tex/context/base/grph-inc.mkii
+++ b/tex/context/base/grph-inc.mkii
@@ -476,7 +476,10 @@
\fi}
\def\externalfigurestamp % needs \edef'd macros!
- {\wantedfigurename
+ {\ifx\wantedfigurepath\empty\else
+ -\wantedfigurepath
+ \fi
+ \wantedfigurename
\ifx\wantedfiguretype\empty\else
\ifx\wantedfiguretype\s!unknown\else
-\wantedfiguretype
diff --git a/tex/context/base/l-aux.lua b/tex/context/base/l-aux.lua
index 39b8f9546..8d74ec178 100644
--- a/tex/context/base/l-aux.lua
+++ b/tex/context/base/l-aux.lua
@@ -221,3 +221,21 @@ function aux.accesstable(target)
end
return t
end
+
+-- as we use this a lot ...
+
+--~ function aux.cachefunction(action,weak)
+--~ local cache = { }
+--~ if weak then
+--~ setmetatable(cache, { __mode = "kv" } )
+--~ end
+--~ local function reminder(str)
+--~ local found = cache[str]
+--~ if not found then
+--~ found = action(str)
+--~ cache[str] = found
+--~ end
+--~ return found
+--~ end
+--~ return reminder, cache
+--~ end
diff --git a/tex/context/base/l-file.lua b/tex/context/base/l-file.lua
index bdb4872d7..8cc50a6aa 100644
--- a/tex/context/base/l-file.lua
+++ b/tex/context/base/l-file.lua
@@ -230,11 +230,11 @@ local rootbased = lpeg.P("/") + letter*lpeg.P(":")
-- ./name ../name /name c: :// name/name
function file.is_qualified_path(filename)
- return qualified:match(filename)
+ return qualified:match(filename) ~= nil
end
function file.is_rootbased_path(filename)
- return rootbased:match(filename)
+ return rootbased:match(filename) ~= nil
end
local slash = lpeg.S("\\/")
diff --git a/tex/context/base/l-lpeg.lua b/tex/context/base/l-lpeg.lua
index 41dc2769b..2c95730c4 100644
--- a/tex/context/base/l-lpeg.lua
+++ b/tex/context/base/l-lpeg.lua
@@ -100,3 +100,15 @@ function string:split(separator)
end
return c:match(self)
end
+
+--~ function lpeg.L(list,pp)
+--~ local p = pp
+--~ for l=1,#list do
+--~ if p then
+--~ p = p + lpeg.P(list[l])
+--~ else
+--~ p = lpeg.P(list[l])
+--~ end
+--~ end
+--~ return p
+--~ end
diff --git a/tex/context/base/l-table.lua b/tex/context/base/l-table.lua
index e14514291..9e0b12f7c 100644
--- a/tex/context/base/l-table.lua
+++ b/tex/context/base/l-table.lua
@@ -26,6 +26,14 @@ function table.strip(tab)
return lst
end
+function table.keys(t)
+ local k = { }
+ for key,_ in next, t do
+ k[#k+1] = key
+ end
+ return k
+end
+
local function compare(a,b)
return (tostring(a) < tostring(b))
end
@@ -798,22 +806,6 @@ function table.reverse(t)
return tt
end
---~ function table.keys(t)
---~ local k = { }
---~ for k,_ in next, t do
---~ k[#k+1] = k
---~ end
---~ return k
---~ end
-
---~ function table.keys_as_string(t)
---~ local k = { }
---~ for k,_ in next, t do
---~ k[#k+1] = k
---~ end
---~ return concat(k,"")
---~ end
-
function table.insert_before_value(t,value,extra)
for i=1,#t do
if t[i] == extra then
diff --git a/tex/context/base/l-xml.lua b/tex/context/base/l-xml.lua
index cd4a797b0..8d1284daa 100644
--- a/tex/context/base/l-xml.lua
+++ b/tex/context/base/l-xml.lua
@@ -8,10 +8,8 @@ if not modules then modules = { } end modules ['l-xml'] = {
-- RJ: key=value ... lpeg.Ca(lpeg.Cc({}) * (pattern-producing-key-and-value / rawset)^0)
--- this module needs a cleanup: check latest lpeg, passing args, (sub)grammar, etc etc
--- some code may move to l-xmlext
--- some day we will really compile the lpaths (just construct functions)
--- todo: some things per xml file, like namespace remapping
+-- this file has been replaced by the lxml-* files and in due time this will become
+-- a stub (currently it's used in some workflows)
--[[ldx--
<p>The parser used here is inspired by the variant discussed in the lua book, but
diff --git a/tex/context/base/luat-lib.mkiv b/tex/context/base/luat-lib.mkiv
index f3c383ae5..d1aea092c 100644
--- a/tex/context/base/luat-lib.mkiv
+++ b/tex/context/base/luat-lib.mkiv
@@ -42,7 +42,13 @@
\registerctxluafile{luat-ini} {1.001}
\registerctxluafile{luat-env} {1.001}
-\registerctxluafile{l-xml} {1.001} % we need to load lxml-tab earlier so this will change ! ! ! ! ! ! !
+%registerctxluafile{l-xml} {1.001} % we need to load lxml-tab earlier so this will change ! ! ! ! ! ! !
+\registerctxluafile{lxml-tab} {1.001}
+\registerctxluafile{lxml-lpt} {1.001}
+\registerctxluafile{lxml-xml} {1.001}
+\registerctxluafile{lxml-aux} {1.001}
+\registerctxluafile{lxml-mis} {1.001}
+\registerctxluafile{lxml-ent} {1.001}
\startruntimeluacode
\edef\asciia{\ctxlua{tex.sprint(logs.mode)}}
diff --git a/tex/context/base/lxml-aux.lua b/tex/context/base/lxml-aux.lua
new file mode 100644
index 000000000..ccff8e90d
--- /dev/null
+++ b/tex/context/base/lxml-aux.lua
@@ -0,0 +1,428 @@
+if not modules then modules = { } end modules ['lxml-aux'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- not all functions here make sense anymore vbut we keep them for
+-- compatibility reasons
+
+local xmlparseapply, xmlconvert, xmlcopy = xml.parse_apply, xml.convert, xml.copy
+
+local type = type
+local insert, remove = table.insert, table.remove
+local gmatch, gsub = string.gmatch, string.gsub
+
+local function withelements(e,handle,depth)
+ if e and handle then
+ local edt = e.dt
+ if edt then
+ depth = depth or 0
+ for i=1,#edt do
+ local e = edt[i]
+ if type(e) == "table" then
+ handle(e,depth)
+ withelements(e,handle,depth+1)
+ end
+ end
+ end
+ end
+end
+
+xml.withelements = withelements
+
+function xml.withelement(e,n,handle) -- slow
+ if e and n ~= 0 and handle then
+ local edt = e.dt
+ if edt then
+ if n > 0 then
+ for i=1,#edt do
+ local ei = edt[i]
+ if type(ei) == "table" then
+ if n == 1 then
+ handle(ei)
+ return
+ else
+ n = n - 1
+ end
+ end
+ end
+ elseif n < 0 then
+ for i=#edt,1,-1 do
+ local ei = edt[i]
+ if type(ei) == "table" then
+ if n == -1 then
+ handle(ei)
+ return
+ else
+ n = n + 1
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+xml.elements_only = xml.collected
+
+function xml.each_element(root, pattern, handle, reverse)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ if reverse then
+ for c=#collected,1,-1 do
+ handle(collected[c])
+ end
+ else
+ for c=1,#collected do
+ handle(collected[c])
+ end
+ end
+ return collected
+ end
+end
+
+xml.process_elements = xml.each_element
+
+function xml.process_attributes(root, pattern, handle)
+ local collected = xmlparseapply({ root },pattern)
+ if collected and handle then
+ for c=1,#collected do
+ handle(collected[c].at)
+ end
+ end
+ return collected
+end
+
+--[[ldx--
+<p>The following functions collect elements and texts.</p>
+--ldx]]--
+
+-- are these still needed -> lxml-cmp.lua
+
+function xml.collect_elements(root, pattern)
+ return xmlparseapply({ root },pattern)
+end
+
+function xml.collect_texts(root, pattern, flatten) -- todo: variant with handle
+ local collected = xmlparseapply({ root },pattern)
+ if collected and flatten then
+ local xmltostring = xml.tostring
+ for c=1,#collected do
+ collected[c] = xmltostring(collected[c])
+ end
+ end
+ return collected or { }
+end
+
+function xml.collect_tags(root, pattern, nonamespace)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ local t = { }
+ for c=1,#collected do
+ local e = collected[c]
+ local ns, tg = e.ns, e.tg
+ if nonamespace then
+ t[#t+1] = tg
+ elseif ns == "" then
+ t[#t+1] = tg
+ else
+ t[#t+1] = ns .. ":" .. tg
+ end
+ end
+ return t
+ end
+end
+
+--[[ldx--
+<p>We've now arrives at the functions that manipulate the tree.</p>
+--ldx]]--
+
+local no_root = { no_root = true }
+
+function xml.inject_element(root, pattern, element, prepend)
+ if root and element then
+ if type(element) == "string" then
+ element = xmlconvert(element,no_root)
+ end
+ if element then
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ local r = e.__p__
+ local d = r.dt
+ local k = e.ni
+ if element.ri then
+ element = element.dt[element.ri].dt
+ else
+ element = element.dt
+ end
+ local edt
+ if r.ri then
+ edt = r.dt[r.ri].dt
+ else
+ edt = d and d[k] and d[k].dt
+ end
+ if edt then
+ local be, af
+ if prepend then
+ be, af = xmlcopy(element), edt
+ else
+ be, af = edt, xmlcopy(element)
+ end
+ for i=1,#af do
+ be[#be+1] = af[i]
+ end
+ if r.ri then
+ r.dt[r.ri].dt = be
+ else
+ d[k].dt = be
+ end
+ else
+ -- r.dt = element.dt -- todo
+ end
+ end
+ end
+ end
+ end
+end
+
+-- todo: copy !
+
+function xml.insert_element(root, pattern, element, before) -- todo: element als functie
+ if root and element then
+ if pattern == "/" then
+ xml.inject_element(root, pattern, element, before)
+ else
+ local matches, collect = { }, nil
+ if type(element) == "string" then
+ element = xmlconvert(element,true)
+ end
+ if element and element.ri then
+ element = element.dt[element.ri]
+ end
+ if element then
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ local r = e.__p__
+ local d = r.dt
+ local k = e.ni
+ if not before then
+ k = k + 1
+ end
+ if element.tg then
+ insert(d,k,element) -- untested
+ else
+ local edt = element.dt
+ if edt then
+ for i=1,#edt do
+ insert(d,k,edt[i])
+ k = k + 1
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+xml.insert_element_after = xml.insert_element
+xml.insert_element_before = function(r,p,e) xml.insert_element(r,p,e,true) end
+xml.inject_element_after = xml.inject_element
+xml.inject_element_before = function(r,p,e) xml.inject_element(r,p,e,true) end
+
+function xml.delete_element(root, pattern)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ remove(e.__p__.dt,e.ni)
+ e.ni = nil
+ end
+ end
+ return collection
+end
+
+function xml.replace_element(root, pattern, element)
+ if type(element) == "string" then
+ element = xmlconvert(element,true)
+ end
+ if element and element.ri then
+ element = element.dt[element.ri]
+ end
+ if element then
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ e.__p__.dt[e.ni] = element.dt -- maybe not clever enough
+ end
+ end
+ end
+end
+
+local function include(xmldata,pattern,attribute,recursive,loaddata)
+ -- parse="text" (default: xml), encoding="" (todo)
+ -- attribute = attribute or 'href'
+ pattern = pattern or 'include'
+ loaddata = loaddata or io.loaddata
+ local collected = xmlparseapply({ xmldata },pattern)
+ if collected then
+ for c=1,#collected do
+ local ek = collected[c]
+ local name = nil
+ local ekdt = ek.dt
+ local ekat = ek.at
+ local epdt = ek.__p__.dt
+ if not attribute or attribute == "" then
+ name = (type(ekdt) == "table" and ekdt[1]) or ekdt -- ckeck, probably always tab or str
+ end
+ if not name then
+ for a in gmatch(attribute or "href","([^|]+)") do
+ name = ekat[a]
+ if name then break end
+ end
+ end
+ local data = (name and name ~= "" and loaddata(name)) or ""
+ if data == "" then
+ epdt[ek.ni] = "" -- xml.empty(d,k)
+ elseif ekat["parse"] == "text" then
+ -- for the moment hard coded
+ epdt[ek.ni] = xml.escaped(data) -- d[k] = xml.escaped(data)
+ else
+ local settings = xmldata.settings
+ settings.parent_root = xmldata -- to be tested
+ local xi = xmlconvert(data,settings)
+ if not xi then
+ epdt[ek.ni] = "" -- xml.empty(d,k)
+ else
+ if recursive then
+ include(xi,pattern,attribute,recursive,loaddata)
+ end
+ epdt[ek.ni] = xml.body(xi) -- xml.assign(d,k,xi)
+ end
+ end
+ end
+ end
+end
+
+xml.include = include
+
+function xml.strip_whitespace(root, pattern, nolines) -- strips all leading and trailing space !
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for i=1,#collected do
+ local e = collected[i]
+ local edt = e.dt
+ if edt then
+ local t = { }
+ for i=1,#edt do
+ local str = edt[i]
+ if type(str) == "string" then
+ if str == "" then
+ -- stripped
+ else
+ if nolines then
+ str = gsub(str,"[ \n\r\t]+"," ")
+ end
+ if str == "" then
+ -- stripped
+ else
+ t[#t+1] = str
+ end
+ end
+ else
+--~ str.ni = i
+ t[#t+1] = str
+ end
+ end
+ e.dt = t
+ end
+ end
+ end
+end
+
+local function rename_space(root, oldspace, newspace) -- fast variant
+ local ndt = #root.dt
+ for i=1,ndt or 0 do
+ local e = root[i]
+ if type(e) == "table" then
+ if e.ns == oldspace then
+ e.ns = newspace
+ if e.rn then
+ e.rn = newspace
+ end
+ end
+ local edt = e.dt
+ if edt then
+ rename_space(edt, oldspace, newspace)
+ end
+ end
+ end
+end
+
+xml.rename_space = rename_space
+
+function xml.remap_tag(root, pattern, newtg)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ collected[c].tg = newtg
+ end
+ end
+end
+
+function xml.remap_namespace(root, pattern, newns)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ collected[c].ns = newns
+ end
+ end
+end
+
+function xml.check_namespace(root, pattern, newns)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ if (not e.rn or e.rn == "") and e.ns == "" then
+ e.rn = newns
+ end
+ end
+ end
+end
+
+function xml.remap_name(root, pattern, newtg, newns, newrn)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ e.tg, e.ns, e.rn = newtg, newns, newrn
+ end
+ end
+end
+
+--[[ldx--
+<p>Here are a few synonyms.</p>
+--ldx]]--
+
+xml.each = xml.each_element
+xml.process = xml.process_element
+xml.strip = xml.strip_whitespace
+xml.collect = xml.collect_elements
+xml.all = xml.collect_elements
+
+xml.insert = xml.insert_element_after
+xml.inject = xml.inject_element_after
+xml.after = xml.insert_element_after
+xml.before = xml.insert_element_before
+xml.delete = xml.delete_element
+xml.replace = xml.replace_element
diff --git a/tex/context/base/lxml-dir.lua b/tex/context/base/lxml-dir.lua
new file mode 100644
index 000000000..12d7680ed
--- /dev/null
+++ b/tex/context/base/lxml-dir.lua
@@ -0,0 +1,107 @@
+if not modules then modules = { } end modules ['lxml-dir'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, gsub = string.format, string.gsub
+local get_id = lxml.id
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+local xmlparseapply = xml.parse_apply
+
+--~ <?xml version="1.0" standalone="yes"?>
+--~ <!-- demo.cdx -->
+--~ <directives>
+--~ <!--
+--~ <directive attribute='id' value="100" setup="cdx:100"/>
+--~ <directive attribute='id' value="101" setup="cdx:101"/>
+--~ -->
+--~ <!--
+--~ <directive attribute='cdx' value="colors" element="cals:table" setup="cdx:cals:table:colors"/>
+--~ <directive attribute='cdx' value="vertical" element="cals:table" setup="cdx:cals:table:vertical"/>
+--~ <directive attribute='cdx' value="noframe" element="cals:table" setup="cdx:cals:table:noframe"/>
+--~ -->
+--~ <directive attribute='cdx' value="*" element="cals:table" setup="cdx:cals:table:*"/>
+--~ </directives>
+
+
+
+lxml.directives = lxml.directives or { }
+
+local directives = lxml.directives
+
+local data = {
+ setup = { },
+ before = { },
+ after = { }
+}
+
+local function load_setup(filename)
+ local fullname = resolvers.find_file(filename) or ""
+ if fullname ~= "" then
+ filename = fullname
+ end
+ local collection = xmlparseapply({ get_id(xml.load(filename)) },"directive")
+ if collection then
+ for i=1,#collection do
+ local at = collection[i].at
+ local attribute, value, element = at.attribute or "", at.value or "", at.element or '*'
+ local setup, before, after = at.setup or "", at.before or "", at.after or ""
+ if attribute ~= "" and value ~= "" then
+ local key = format("%s::%s::%s",element,attribute,value)
+ local t = data[key] or { }
+ if setup ~= "" then t.setup = setup end
+ if before ~= "" then t.before = before end
+ if after ~= "" then t.after = after end
+ data[key] = t
+ end
+ end
+ end
+end
+
+local function handle_setup(category,root,attribute,element)
+ root = get_id(root)
+ if attribute then
+ local value = root.at[attribute]
+ if value then
+ if not element then
+ local ns, tg = root.rn or root.ns, root.tg
+ if ns == "" then
+ element = tg
+ else
+ element = ns .. ':' .. tg
+ end
+ end
+ local setup = data[format("%s::%s::%s",element,attribute,value)]
+ if setup then
+ setup = setup[category]
+ end
+ if setup then
+ texsprint(ctxcatcodes,"\\directsetup{",setup,"}")
+ else
+ setup = data[format("%s::%s::*",element,attribute)]
+ if setup then
+ setup = setup[category]
+ end
+ if setup then
+ texsprint(ctxcatcodes,"\\directsetup{",gsub(setup,'%*',value),"}")
+ end
+ end
+ end
+ end
+end
+
+directives.load = load_setup
+directives.handle = handle_setup
+
+function directives.setup(root,attribute,element)
+ handle_setup('setup',root,attribute,element)
+end
+function directives.before(root,attribute,element)
+ handle_setup('before',root,attribute,element)
+end
+function directives.after(root,attribute,element)
+ handle_setup('after',root,attribute,element)
+end
diff --git a/tex/context/base/lxml-ent.lua b/tex/context/base/lxml-ent.lua
index c91d12706..69c37e8f9 100644
--- a/tex/context/base/lxml-ent.lua
+++ b/tex/context/base/lxml-ent.lua
@@ -6,102 +6,21 @@ if not modules then modules = { } end modules ['lxml-ent'] = {
license = "see context related readme files"
}
-local type, next, tonumber, tostring, setmetatable, loadstring = type, next, tonumber, tostring, setmetatable, loadstring
-local format, gsub, find = string.format, string.gsub, string.find
-local utfchar = unicode.utf8.char
+local type, next = type, next
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+local utfupper = utf.upper
--[[ldx--
<p>We provide (at least here) two entity handlers. The more extensive
resolver consults a hash first, tries to convert to <l n='utf'/> next,
and finaly calls a handler when defines. When this all fails, the
original entity is returned.</p>
+
+<p>We do things different now but it's still somewhat experimental</p>
--ldx]]--
xml.entities = xml.entities or { } -- xml.entity_handler == function
-function xml.entity_handler(e)
- return format("[%s]",e)
-end
-
-local function toutf(s)
- return utfchar(tonumber(s,16))
-end
-
-local function utfize(root)
- local d = root.dt
- for k=1,#d do
- local dk = d[k]
- if type(dk) == "string" then
- -- test prevents copying if no match
- if find(dk,"&#x.-;") then
- d[k] = gsub(dk,"&#x(.-);",toutf)
- end
- else
- utfize(dk)
- end
- end
-end
-
-xml.utfize = utfize
-
-local function resolve(e) -- hex encoded always first, just to avoid mkii fallbacks
- if find(e,"^#x") then
- return utfchar(tonumber(e:sub(3),16))
- elseif find(e,"^#") then
- return utfchar(tonumber(e:sub(2)))
- else
- local ee = xml.entities[e] -- we cannot shortcut this one (is reloaded)
- if ee then
- return ee
- else
- local h = xml.entity_handler
- return (h and h(e)) or "&" .. e .. ";"
- end
- end
-end
-
-local function resolve_entities(root)
- if not root.special or root.tg == "@rt@" then
- local d = root.dt
- for k=1,#d do
- local dk = d[k]
- if type(dk) == "string" then
- if find(dk,"&.-;") then
- d[k] = gsub(dk,"&(.-);",resolve)
- end
- else
- resolve_entities(dk)
- end
- end
- end
-end
-
-xml.resolve_entities = resolve_entities
-
-function xml.utfize_text(str)
- if find(str,"&#") then
- return (gsub(str,"&#x(.-);",toutf))
- else
- return str
- end
-end
-
-function xml.resolve_text_entities(str) -- maybe an lpeg. maybe resolve inline
- if find(str,"&") then
- return (gsub(str,"&(.-);",resolve))
- else
- return str
- end
-end
-
-function xml.show_text_entities(str)
- if find(str,"&") then
- return (gsub(str,"&(.-);","[%1]"))
- else
- return str
- end
-end
-
-- experimental, this will be done differently
function xml.merge_entities(root)
@@ -113,3 +32,21 @@ function xml.merge_entities(root)
end
end
end
+
+function xml.resolved_entity(str)
+ local e = xml.entities[str]
+ if e then
+ local te = type(e)
+ if te == "function" then
+ e(str)
+ else
+ texsprint(ctxcatcodes,e)
+ end
+ else
+ texsprint(ctxcatcodes,"\\xmle{",str,"}{",utfupper(str),"}") -- we need to use our own upper
+ end
+end
+
+xml.entities.amp = function() tex.write("&") end
+xml.entities.lt = function() tex.write("<") end
+xml.entities.gt = function() tex.write(">") end
diff --git a/tex/context/base/lxml-inf.lua b/tex/context/base/lxml-inf.lua
new file mode 100644
index 000000000..629c869ec
--- /dev/null
+++ b/tex/context/base/lxml-inf.lua
@@ -0,0 +1,53 @@
+if not modules then modules = { } end modules ['lxml-inf'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This file will be loaded runtime by x-pending.tex.
+
+local status, stack
+
+local function get(e,d)
+ local ns, tg = e.ns, e.tg
+ local name = tg
+ if ns ~= "" then name = ns .. ":" .. tg end
+ stack[d] = name
+ local ec = e.command
+ if ec == true then
+ ec = "system: text"
+ elseif ec == false then
+ ec = "system: skip"
+ elseif ec == nil then
+ ec = "system: not set"
+ elseif type(ec) == "string" then
+ ec = "setup: " .. ec
+ else -- function
+ ec = tostring(ec)
+ end
+ local tag = concat(stack," => ",1,d)
+ local s = status[tag]
+ if not s then
+ s = { }
+ status[tag] = s
+ end
+ s[ec] = (s[ec] or 0) + 1
+end
+
+local function get_command_status(id)
+ status, stack = {}, {}
+ if id then
+ xmlwithelements(get_id(id),get)
+ return status
+ else
+ local t = { }
+ for id, _ in next, loaded do
+ t[id] = get_command_status(id)
+ end
+ return t
+ end
+end
+
+lxml.get_command_status = get_command_status
diff --git a/tex/context/base/lxml-ini.lua b/tex/context/base/lxml-ini.lua
deleted file mode 100644
index cc4b953cd..000000000
--- a/tex/context/base/lxml-ini.lua
+++ /dev/null
@@ -1,1390 +0,0 @@
-if not modules then modules = { } end modules ['lxml-ini'] = {
- version = 1.001,
- comment = "companion to lxml-ini.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local utf = unicode.utf8
-local tex = tex or {}
-
-local texsprint, texprint, texwrite, utfchar = tex.sprint or print, tex.print or print, tex.write or print, utf.char
-local concat, insert, remove, gsub, find = table.concat, table.insert, table.remove
-local format, sub, gsub, find = string.format, string.sub, string.gsub, string.find
-local type, next, tonumber, tostring = type, next, tonumber, tostring
-
-local ctxcatcodes = tex.ctxcatcodes
-local texcatcodes = tex.texcatcodes
-local vrbcatcodes = tex.vrbcatcodes
-
-local trace_setups = false trackers.register("lxml.setups", function(v) trace_setups = v end)
-local trace_loading = false trackers.register("lxml.loading", function(v) trace_loading = v end)
-local trace_access = false trackers.register("lxml.access", function(v) trace_access = v end)
-
--- todo: speed up: remember last index/match combination
-
-local traverse, lpath = xml.traverse, xml.lpath
-
-local xmlfilter, xmlfirst, xmllast, xmlall, xmlcount = xml.filter, xml.first, xml.last, xml.all, xml.count
-local xmlcollect, xmlcontent, xmlcollect_texts, xmlcollect_tags, xmlcollect_elements = xml.collect, xml.content, xml.collect_texts, xml.collect_tags, xml.collect_elements
-local xmlattribute, xmlindex, xmlchainattribute = xml.filters.attribute, xml.filters.index, xml.filters.chainattribute
-local xmlelements, xmlsetproperty = xml.elements, xml.setproperty
-
-document = document or { }
-document.xml = document.xml or { }
-
--- todo: loaded and myself per document so that we can garbage collect buffers
-
-lxml = lxml or { }
-lxml.loaded = { }
-lxml.noffiles = 0
-lxml.nofconverted = 0
-lxml.nofindices = 0
-
-local loaded = lxml.loaded
-
--- experiment
-
-function lxml.store(id,root,filename)
- loaded[id] = root
- xmlsetproperty(root,"name",id)
- if filename then
- xmlsetproperty(root,"filename",filename)
- end
-end
-
---~ local currentdocuments, currentloaded, currentdocument, defaultdocument = { }, { }, "", ""
-
---~ function lxml.pushdocument(name) -- catches double names
---~ if #currentdocuments == 0 then
---~ defaultdocument = name
---~ end
---~ currentdocument = name
---~ insert(currentdocuments,currentdocument)
---~ insert(currentloaded,loaded[currentdocument])
---~ if trace_access then
---~ logs.report("lxml","pushed: %s",currentdocument)
---~ end
---~ end
-
---~ function lxml.popdocument()
---~ currentdocument = remove(currentdocuments)
---~ if not currentdocument or currentdocument == "" then
---~ currentdocument = defaultdocument
---~ end
---~ loaded[currentdocument] = remove(currentloaded)
---~ if trace_access then
---~ logs.report("lxml","popped: %s",currentdocument)
---~ end
---~ end
-
---~ local splitter = ((lpeg.R("09")^1/tonumber) + lpeg.Cc(false)) * lpeg.P("@")^0 * (lpeg.C(lpeg.P(1)^1) + lpeg.Cc(false))
-
-local splitter = lpeg.C((1-lpeg.P(":"))^1) * lpeg.P("::") * lpeg.C(lpeg.P(1)^1)
-
-lxml.idsplitter = splitter
-
-function lxml.splitid(id)
- local d, i = splitter:match(id)
- if d then
- return d, i
- else
- return "", id
- end
-end
-
-local function get_id(id, qualified)
- if type(id) == "table" then
- return id
- else
- local lid = loaded[id]
- if lid then
- return lid
- else
- local d, i = splitter:match(id)
- if d then
- local ld = loaded[d]
- if ld then
- local ldi = ld.index
- if ldi then
- local root = ldi[tonumber(i)]
- if root then
- if qualified then -- we need this else two args that confuse others
- return root, d
- else
- return root
- end
- elseif trace_access then
- logs.report("lxml","'%s' has no index entry '%s'",d,i)
- end
- elseif trace_access then
- logs.report("lxml","'%s' has no index",d)
- end
- elseif trace_access then
- logs.report("lxml","'%s' is not loaded",d)
- end
- else
---~ local ld = loaded[currentdocument]
---~ if ld then
---~ local ldi = ld.index
---~ if ldi then
---~ local root = ldi[tonumber(id)]
---~ if root then
---~ if qualified then -- we need this else two args that confuse others
---~ return root, currentdocument
---~ else
---~ return root
---~ end
---~ elseif trace_access then
---~ logs.report("lxml","current document '%s' has no index entry '%s'",currentdocument,id)
---~ end
---~ elseif trace_access then
---~ logs.report("lxml","current document '%s' has no index",currentdocument)
---~ end
---~ elseif trace_access then
---~ logs.report("lxml","current document '%s' not loaded",currentdocument)
---~ end
- end
- end
- end
-end
-
-lxml.id = get_id
-
-function lxml.root(id)
- return loaded[id]
-end
-
-do
-
- xml.specialhandler = xml.specialhandler or { }
-
- local specialhandler = xml.specialhandler
- local serialize = xml.serialize
-
- local crlf = lpeg.P("\r\n")
- local cr = lpeg.P("\r")
- local lf = lpeg.P("\n")
- local space = lpeg.S(" \t\f\v")
- local newline = crlf + cr + lf
- local spacing = newline * space^0
- local content = lpeg.C((1-spacing)^1)
- local verbose = lpeg.C((1-(space+newline))^1)
-
- -- local capture = (
- -- newline^2 * lpeg.Cc("") / texprint +
- -- newline * lpeg.Cc(" ") / texsprint +
- -- content / texsprint
- -- )^0
-
- local capture = (
- space^0 * newline^2 * lpeg.Cc("") / texprint +
- space^0 * newline * space^0 * lpeg.Cc(" ") / texsprint +
- content / texsprint
- )^0
-
- local forceraw, rawroot = false, nil
-
- function lxml.startraw()
- forceraw = true
- end
- function lxml.stopraw()
- forceraw = false
- end
- function lxml.rawroot()
- return rawroot
- end
- function lxml.rawpath(rootid)
- if rawroot and type(rawroot) == "table" then
- local text, path, rp
- if not rawroot.dt then
- text, path, rp = "text", "", rawroot[0]
- else
- path, rp = "tree", "", rawroot.__p__
- end
- while rp do
- local rptg = rp.tg
- if rptg then
- path = rptg .. "/" .. path
- end
- rp = rp.__p__
- end
- return { rootid, "/" .. path, text }
- end
- end
-
- local function sprint(root)
- if not root then
- --~ rawroot = false
- -- quit
- else
- local tr = type(root)
- if tr == "string" then -- can also be result of lpath
- --~ rawroot = false
- capture:match(root)
- elseif tr == "table" then
- rawroot = forceraw and root
- serialize(root,sprint,nil,nil,specialhandler,forceraw)
- end
- end
- end
-
- xml.sprint = sprint
-
- function xml.tprint(root) -- we can move sprint inline
- local tr = type(root)
- if tr == "table" then
- local n = #root
- if n == 0 then
- sprint("") -- empty element, else no setup triggered (check this! )
- else
- for i=1,n do
- sprint(root[i])
- end
- end
- elseif tr == "string" then
- sprint(root)
- end
- end
-
- function xml.cprint(root) -- content
- if not root then
---~ rawroot = false
- -- quit
- elseif type(root) == 'string' then
---~ rawroot = false
- capture:match(root)
- else
- local rootdt = root.dt
- rawroot = forceraw and root
- if rootdt then -- the main one
- serialize(rootdt,sprint,nil,nil,specialhandler,forceraw)
- else -- probably dt
- serialize(root,sprint,nil,nil,specialhandler,forceraw)
- end
- end
- end
-
- -- lines (untested)
-
- local buffer = { }
-
- local capture = (
- newline^2 / function() buffer[#buffer+1] = "" end +
- newline / function() buffer[#buffer] = buffer[#buffer] .. " " end +
- content / function(s) buffer[#buffer] = buffer[#buffer] .. s end
- )^0
-
- function lines(root)
- if not root then
---~ rawroot = false
- -- quit
- elseif type(root) == 'string' then
---~ rawroot = false
- capture:match(root)
- elseif next(root) then -- tr == 'table'
- rawroot = forceraw and root
- serialize(root,lines,forceraw)
- end
- end
-
- function xml.lines(root)
- buffer = { "" }
- lines(root)
- return result
- end
-
- -- cdata
-
- local linecommand = "\\obeyedline"
- local spacecommand = "\\obeyedspace" -- "\\strut\\obeyedspace"
- local beforecommand = ""
- local aftercommand = ""
-
- local capture = (
- newline / function( ) texsprint(texcatcodes,linecommand,"{}") end +
- verbose / function(s) texsprint(vrbcatcodes,s) end +
- space / function( ) texsprint(texcatcodes,spacecommand,"{}") end
- )^0
-
- local function toverbatim(str)
- if beforecommand then texsprint(texcatcodes,beforecommand,"{}") end
- capture:match(str)
- if aftercommand then texsprint(texcatcodes,aftercommand,"{}") end
- end
-
- function lxml.set_verbatim(before,after,obeyedline,obeyedspace)
- beforecommand, aftercommand, linecommand, spacecommand = before, after, obeyedline, obeyedspace
- end
-
- function lxml.set_cdata()
- specialhandler['@cd@'] = toverbatim
- end
-
- function lxml.reset_cdata()
- specialhandler['@cd@'] = nil
- end
-
- -- local capture = (space^0*newline)^0 * capture * (space+newline)^0 * -1
-
- local function toverbatim(str)
- if beforecommand then texsprint(texcatcodes,beforecommand,"{}") end
- -- todo: add this to capture
- str = gsub(str,"^[ \t]+[\n\r]+","")
- str = gsub(str,"[ \t\n\r]+$","")
- capture:match(str)
- if aftercommand then texsprint(texcatcodes,aftercommand,"{}") end
- end
-
- function lxml.verbatim(id,before,after)
- local root = get_id(id)
- if root then
- if before then texsprint(ctxcatcodes,format("%s[%s]",before,root.tg)) end
- -- serialize(root.dt,toverbatim,nil,nil,nil,true) -- was root
- local t = { }
- serialize(root.dt,function(s) t[#t+1] = s end,nil,nil,nil,true) -- was root
- toverbatim(table.concat(t,""))
- if after then texsprint(ctxcatcodes,after) end
- end
- end
- function lxml.inlineverbatim(id)
- lxml.verbatim(id,"\\startxmlinlineverbatim","\\stopxmlinlineverbatim")
- end
- function lxml.displayverbatim(id)
- lxml.verbatim(id,"\\startxmldisplayverbatim","\\stopxmldisplayverbatim")
- end
-
- local pihandlers = { }
-
- specialhandler['@pi@'] = function(str)
- for i=1,#pihandlers do
- pihandlers[i](str)
- end
- end
-
- xml.pihandlers = pihandlers
-
- local kind = lpeg.P("context-") * lpeg.C((1-lpeg.P("-"))^1) * lpeg.P("-directive")
- local space = lpeg.S(" \n\r")
- local spaces = space^0
- local class = lpeg.C((1-space)^0)
- local key = class
- local value = lpeg.C(lpeg.P(1-(space * -1))^0)
-
- local parser = kind * spaces * class * spaces * key * spaces * value
-
- pihandlers[#pihandlers+1] = function(str)
- -- local kind, class, key, value = parser:match(str)
- if str then
- local a, b, c, d = parser:match(str)
- if d then
- texsprint(ctxcatcodes,format("\\xmlcontextdirective{%s}{%s}{%s}{%s}",a,b,c,d))
- end
- end
- end
-
- -- print(contextdirective("context-mathml-directive function reduction yes "))
- -- print(contextdirective("context-mathml-directive function "))
-
- function lxml.main(id)
- serialize(get_id(id),sprint,nil,nil,specialhandler) -- the real root (@rt@)
- end
-
- specialhandler['@dt@'] = function()
- -- nothing
- end
-
-end
-
-local xmlsprint = xml.sprint
-local xmltprint = xml.tprint
-
--- redefine xml load
-
-xml.originalload = xml.originalload or xml.load
-
-local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
-
-function xml.load(filename)
- lxml.noffiles = lxml.noffiles + 1
- lxml.nofconverted = lxml.nofconverted + 1
- starttiming(xml)
- local ok, data = resolvers.loadbinfile(filename)
- local xmltable = xml.convert((ok and data) or "")
- stoptiming(xml)
- return xmltable
-end
-
-function lxml.load(id,filename)
- filename = commands.preparedfile(filename)
- if trace_loading then
- commands.writestatus("lxml","loading file '%s' as '%s'",filename,id)
- end
- local xmltable = xml.load(filename)
- lxml.store(id,xmltable,filename)
- return xmltable, filename
-end
-
-function lxml.register(id,xmltable,filename)
- lxml.store(id,xmltable,filename)
- return xmltable
-end
-
-function lxml.include(id,pattern,attribute,recurse)
- starttiming(xml)
- local root = get_id(id)
- xml.include(root,pattern,attribute,recurse,function(filename)
- if filename then
- filename = commands.preparedfile(filename)
- if file.dirname(filename) == "" and root.filename then
- filename = file.join(file.dirname(root.filename),filename)
- end
- if trace_loading then
- commands.writestatus("lxml","including file: %s",filename)
- end
- lxml.noffiles = lxml.noffiles + 1
- lxml.nofconverted = lxml.nofconverted + 1
- return resolvers.loadtexfile(filename) or ""
- else
- return ""
- end
- end)
- stoptiming(xml)
-end
-
-function lxml.utfize(id)
- xml.utfize(get_id(id))
-end
-
-function lxml.filter(id,pattern)
- xmlsprint(xmlfilter(get_id(id),pattern))
-end
-function lxml.first(id,pattern)
- xmlsprint(xmlfirst(get_id(id),pattern))
-end
-function lxml.last(id,pattern)
- xmlsprint(xmllast(get_id(id),pattern))
-end
-function lxml.all(id,pattern)
- traverse(get_id(id), lpath(pattern), function(r,d,k)
- if d then
- xmlsprint(d[k])
- end
- return false
- end)
-end
-
-function lxml.nonspace(id,pattern) -- slow, todo loop
- xmltprint(xmlcollect(get_id(id),pattern,true))
-end
-
-function lxml.strip(id,pattern,nolines)
- xml.strip(get_id(id),pattern,nolines)
-end
-
-function lxml.text(id,pattern)
- -- we can avoid some steps by passing xmlsprint
- xmltprint(xmlcollect_texts(get_id(id),pattern) or {})
-end
-
-function lxml.tags(id,pattern)
- local tags = xmlcollect_tags(get_id(id),pattern)
- if tags then
- texsprint(concat(tags,","))
- end
-end
-
-function lxml.raw(id,pattern) -- the content, untouched by commands
- local c = xmlfilter(get_id(id),pattern)
- if c then
- xml.serialize(c.dt,texsprint,nil,nil,nil,true)
- end
-end
-
-function lxml.snippet(id,i)
- local e = get_id(id)
- if e then
- local edt = e.dt
- if edt then
- xmlsprint(edt[i])
- end
- end
-end
-
-function xml.element(e,n)
- if e then
- local edt = e.dt
- if edt then
- if n > 0 then
- for i=1,#edt do
- local ei = edt[i]
- if type(ei) == "table" then
- if n == 1 then
- xmlsprint(ei)
- return
- else
- n = n - 1
- end
- end
- end
- elseif n < 0 then
- for i=#edt,1,-1 do
- local ei = edt[i]
- if type(ei) == "table" then
- if n == -1 then
- xmlsprint(ei)
- return
- else
- n = n + 1
- end
- end
- end
- end
- end
- end
-end
-
-function lxml.element(id,n)
- xml.element(get_id(id),n)
-end
-
-function lxml.stripped(id,pattern,nolines)
- local str = xmlcontent(get_id(id),pattern) or ""
- str = gsub(str,"^%s*(.-)%s*$","%1")
- if nolines then
- str = gsub(str,"%s+"," ")
- end
- xmlsprint(str)
-end
-
-function lxml.flush(id)
- id = get_id(id)
- local dt = id and id.dt
- if dt then
- xmlsprint(dt)
- end
-end
-
-function lxml.direct(id)
- xmlsprint(get_id(id))
-end
-
-function lxml.index(id,pattern,i)
- xmlsprint((xmlindex(get_id(id),pattern,i)))
-end
-
-function lxml.attribute(id,pattern,a,default) --todo: snelle xmlatt
- local str = xmlattribute(get_id(id),pattern,a) or ""
- texsprint((str == "" and default) or str)
-end
-function lxml.chainattribute(id,pattern,a,default) --todo: snelle xmlatt
- local str = xmlchainattribute(get_id(id),pattern,a) or ""
- texsprint((str == "" and default) or str)
-end
-
-function lxml.count(id,pattern)
- texsprint(xmlcount(get_id(id),pattern) or 0)
-end
-function lxml.nofelements(id)
- local e = get_id(id)
- local edt = e.dt
- if edt and type(edt) == "table" then
- local n = 0
- for i=1,#edt do
- if type(edt[i]) == "table" then
- n = n + 1
- end
- end
- texsprint(n)
- else
- texsprint(0)
- end
-end
-function lxml.name(id) -- or remapped name? -> lxml.info, combine
- local r = get_id(id)
- local ns = r.rn or r.ns or ""
- if ns ~= "" then
- texsprint(ns,":",r.tg)
- else
- texsprint(r.tg)
- end
-end
-function lxml.tag(id) -- tag vs name -> also in l-xml tag->name
- texsprint(get_id(id).tg or "")
-end
-function lxml.namespace(id) -- or remapped name?
- local root = get_id(id)
- texsprint(root.rn or root.ns or "")
-end
-
---~ function lxml.concat(id,what,separator,lastseparator)
---~ texsprint(concat(xml.collect_texts(get_id(id),what,true),separator or ""))
---~ end
-
-function lxml.concatrange(id,what,start,stop,separator,lastseparator) -- test this on mml
- local t = xmlcollect_elements(get_id(id),what,true) -- ignorespaces
- local separator = separator or ""
- local lastseparator = lastseparator or separator or ""
- start, stop = (start == "" and 1) or tonumber(start) or 1, (stop == "" and #t) or tonumber(stop) or #t
- if stop < 0 then stop = #t + stop end -- -1 == last-1
- for i=start,stop do
- xmlsprint(t[i])
- if i == #t then
- -- nothing
- elseif i == #t-1 and lastseparator ~= "" then
- texsprint(ctxcatcodes,lastseparator)
- elseif separator ~= "" then
- texsprint(ctxcatcodes,separator)
- end
- end
-end
-
-function lxml.concat(id,what,separator,lastseparator)
- lxml.concatrange(id,what,false,false,separator,lastseparator)
-end
-
--- string : setup
--- true : text (no <self></self>)
--- false : ignore
--- function : call
-
--- todo: free self after usage, i.e. after the setup, which
--- means a call to lua; we can also choose a proper maximum
--- and cycle or maybe free on demand
-
--- problems with empty elements
--- we use a real tex.sprint, else spaces go wrong
--- maybe just a .. because this happens often
-
-function lxml.serialize(root, command)
- local tc = type(command)
- if tc == "string" then
- -- setup
- local ix = root.ix
- local rootname = root.name
- if rootname then
- if not ix then
- lxml.addindex(rootname,false,true)
- ix = root.ix
- end
---~ print(rootname,ix,command)
- texsprint(ctxcatcodes,format("\\xmls{%s::%s}{%s}",rootname,ix,command))
- else
---~ print(ix,command)
- texsprint(ctxcatcodes,format("\\xmls{%s}{%s}",ix,command))
- end
- elseif tc == "function" then
- -- function
- command(root)
- elseif command == true then
- -- text (no <self></self>) / so, no mkii fallback then
- xmltprint(root.dt)
- elseif command == false then
- -- ignore
- else
- -- texsprint("?")
- -- fuzzy, so ignore too
- end
-end
-
-xml.setserializer(lxml.serialize)
-
-function lxml.setaction(id,pattern,action)
- for rt, dt, dk in xmlelements(get_id(id),pattern) do
- dt[dk].command = action
- end
-end
-
-function lxml.setsetup(id,pattern,setup)
- if not setup or setup == "" or setup == "*" or setup == "-" or setup == "+" then
- for rt, dt, dk in xmlelements(get_id(id),pattern) do
- local dtdk = dt and dt[dk] or rt
- local ns, tg = dtdk.rn or dtdk.ns, dtdk.tg
- if tg then -- to be sure
- local command = (ns == "" and tg) or (ns .. ":" .. tg)
- if setup == "-" then
- dtdk.command = false
- if trace then
- logs.report("lxml","lpath matched -> %s -> skipped", setup)
- end
- elseif setup == "+" then
- dtdk.command = true
- if trace_setups then
- logs.report("lxml","lpath matched -> %s -> text", setup)
- end
- else
- dtdk.command = tg -- command -- setup
- if trace_setups then
- if ns == "" then
- logs.report("lxml","lpath matched -> %s -> %s", tg, tg)
- else
- logs.report("lxml","lpath matched -> %s:%s -> %s", ns, tg, tg)
- end
- end
- end
- end
- end
- else
- local a, b = setup:match("^(.+:)([%*%-])$")
- if a and b then
- for rt, dt, dk in xmlelements(get_id(id),pattern) do
- local dtdk = (dt and dt[dk]) or rt
- local ns, tg = dtdk.rn or dtdk.ns, dtdk.tg
- if b == "-" then
- dtdk.command = false
- if trace_setups then
- if ns == "" then
- logs.report("lxml","lpath matched -> %s -> skipped", tg)
- else
- logs.report("lxml","lpath matched -> %s:%s -> skipped", ns, tg)
- end
- end
- elseif b == "+" then
- dtdk.command = true
- if trace_setups then
- if ns == "" then
- logs.report("lxml","lpath matched -> %s -> text", tg)
- else
- logs.report("lxml","lpath matched -> %s:%s -> text", ns, tg)
- end
- end
- else
- dtdk.command = a .. tg
- if trace_setups then
- if ns == "" then
- logs.report("lxml","lpath matched -> %s -> %s", tg, dtdk.command)
- else
- logs.report("lxml","lpath matched -> %s:%s -> %s", ns, tg, dtdk.command)
- end
- end
- end
- end
- else
- if trace_setups then
- logs.report("lxml","lpath pattern -> %s -> %s", pattern, setup)
- end
- for rt, dt, dk in xmlelements(get_id(id),pattern) do
- local dtdk = (dt and dt[dk]) or rt
- dtdk.command = setup
- if trace_setups then
- local ns, tg = dtdk.rn or dtdk.ns, dtdk.tg
- if ns == "" then
- logs.report("lxml","lpath matched -> %s -> %s", tg, setup)
- else
- logs.report("lxml","lpath matched -> %s:%s -> %s", ns, tg, setup)
- end
- end
- end
- end
- end
-end
-
-function lxml.idx(id,pattern,i) -- hm, hashed, needed?
- local r = get_id(id)
- if r then
- local rp = r.patterns
- if not rp then
- rp = { }
- r.patterns = rp
- end
- if not rp[pattern] then
- rp[pattern] = xmlcollect_elements(r,pattern) -- dd, rr
- end
- local rpi = rp[pattern] and rp[pattern][i]
- if rpi then
- xmlsprint(rpi)
- end
- end
-end
-
-function lxml.info(id)
- id = get_id(id)
- local ns, tg = id.ns, id.tg
- if ns and ns ~= "" then -- best make a function
- tg = ns .. ":" .. tg
- else
- tg = tg or "?"
- end
- texsprint(tg)
-end
-
--- can be simplified ... we can use the outer name
-
---~ local function command(root,pattern,cmd) -- met zonder ''
---~ if find(cmd,"^[\'\"]") then
---~ cmd = sub(cmd,2,-2)
---~ end
---~ local rootname = root.name
---~ traverse(root, lpath(pattern), function(r,d,k)
---~ -- this can become pretty large
---~ local m = (d and d[k]) or r -- brrr this r, maybe away
---~ local ix = m.ix
---~ if not ix then
---~ lxml.addindex(rootname,false,true)
---~ ix = m.ix
---~ end
---~ texsprint(ctxcatcodes,format("\\xmls{%s::%s}{%s}",rootname,ix,cmd))
---~ end)
---~ end
---~ local function qualifiedcommand(parent,root,pattern,cmd) -- met zonder ''
---~ if find(cmd,"^[\'\"]") then
---~ cmd = sub(cmd,2,-2)
---~ end
---~ traverse(root, lpath(pattern), function(r,d,k)
---~ local m = (d and d[k]) or r
---~ local ix = m.ix
---~ if not ix then
---~ lxml.addindex(parent,false,true)
---~ ix = m.ix
---~ end
---~ texsprint(ctxcatcodes,format("\\xmls{%s::%s}{%s}",parent,ix,cmd))
---~ end)
---~ end
-
-local rootname, thecmd
-local function ndoit(r,d,k)
- local m = (d and d[k]) or r
- local ix = m.ix
- if not ix then
- lxml.addindex(rootname,false,true)
- ix = m.ix
- end
- texsprint(ctxcatcodes,format("\\xmls{%s::%s}{%s}",rootname,ix,thecmd))
-end
-local function qdoit(r,d,k)
- local m = (d and d[k]) or r
- local ix = m.ix
- if not ix then
- lxml.addindex(parent,false,true)
- ix = m.ix
- end
- texsprint(ctxcatcodes,format("\\xmls{%s::%s}{%s}",rootname,ix,thecmd))
-end
-local function command(root,pattern,cmd) -- met zonder ''
- if find(cmd,"^[\'\"]") then
- thecmd = sub(cmd,2,-2)
- else
- thecmd = cmd
- end
- rootname = root.name
- traverse(root, lpath(pattern), ndoit)
-end
-local function qualifiedcommand(parent,root,pattern,cmd) -- met zonder ''
- if find(cmd,"^[\'\"]") then
- thecmd = sub(cmd,2,-2)
- else
- thecmd = cmd
- end
- rootname = parent
- traverse(root, lpath(pattern), qdoit)
-end
-
-function lxml.command(id,pattern,cmd)
- if find(cmd,"^[\'\"]") then
- thecmd = sub(cmd,2,-2)
- else
- thecmd = cmd
- end
- local i, p = get_id(id,true)
- if p then
- rootname = p
- traverse(i, lpath(pattern), qdoit)
- else
- rootname = i.name
- traverse(i, lpath(pattern), ndoit)
- end
-end
-
-xml.filters.command = command
-
-local function dofunction(root,pattern,fnc)
- traverse(root, lpath(pattern), xml.functions[fnc]) -- r, d, t
-end
-
-xml.filters["function"] = dofunction
-
---~ <?xml version="1.0" standalone="yes"?>
---~ <!-- demo.cdx -->
---~ <directives>
---~ <!--
---~ <directive attribute='id' value="100" setup="cdx:100"/>
---~ <directive attribute='id' value="101" setup="cdx:101"/>
---~ -->
---~ <!--
---~ <directive attribute='cdx' value="colors" element="cals:table" setup="cdx:cals:table:colors"/>
---~ <directive attribute='cdx' value="vertical" element="cals:table" setup="cdx:cals:table:vertical"/>
---~ <directive attribute='cdx' value="noframe" element="cals:table" setup="cdx:cals:table:noframe"/>
---~ -->
---~ <directive attribute='cdx' value="*" element="cals:table" setup="cdx:cals:table:*"/>
---~ </directives>
-
-lxml.directives = { }
-
-local data = {
- setup = { },
- before = { },
- after = { }
-}
-
-function lxml.directives.load(filename)
- local fullname = resolvers.find_file(filename) or ""
- if fullname ~= "" then
- filename = fullname
- end
- local root = xml.load(filename)
- for r, d, k in xmlelements(root,"directive") do
- local dk = d[k]
- local at = dk.at
- local attribute, value, element = at.attribute or "", at.value or "", at.element or '*'
- local setup, before, after = at.setup or "", at.before or "", at.after or ""
- if attribute ~= "" and value ~= "" then
- local key = format("%s::%s::%s",element,attribute,value)
- local t = data[key] or { }
- if setup ~= "" then t.setup = setup end
- if before ~= "" then t.before = before end
- if after ~= "" then t.after = after end
- data[key] = t
- end
- end
-end
-
-function lxml.directives.setup(root,attribute,element)
- lxml.directives.handle_setup('setup',root,attribute,element)
-end
-function lxml.directives.before(root,attribute,element)
- lxml.directives.handle_setup('before',root,attribute,element)
-end
-function lxml.directives.after(root,attribute,element)
- lxml.directives.handle_setup('after',root,attribute,element)
-end
-
-function lxml.directives.handle_setup(category,root,attribute,element)
- root = get_id(root)
- attribute = attribute
- if attribute then
- local value = root.at[attribute]
- if value then
- if not element then
- local ns, tg = root.rn or root.ns, root.tg
- if ns == "" then
- element = tg
- else
- element = ns .. ':' .. tg
- end
- end
- local setup = data[format("%s::%s::%s",element,attribute,value)]
- if setup then
- setup = setup[category]
- end
- if setup then
- texsprint(ctxcatcodes,format("\\directsetup{%s}",setup))
- else
- setup = data[format("%s::%s::*",element,attribute)]
- if setup then
- setup = setup[category]
- end
- if setup then
- texsprint(ctxcatcodes,format("\\directsetup{%s}",gsub(setup,'%*',value)))
- end
- end
- end
- end
-end
-
-function xml.getbuffer(name) -- we need to make sure that commands are processed
- if not name or name == "" then
- name = tex.jobname
- end
- lxml.nofconverted = lxml.nofconverted + 1
- xml.tostring(xml.convert(concat(buffers.data[name] or {},"")))
-end
-
-function lxml.loadbuffer(id,name)
- if not name or name == "" then
- name = tex.jobname
- end
- starttiming(xml)
- lxml.nofconverted = lxml.nofconverted + 1
- local xmltable = xml.convert(buffers.collect(name or id,"\n"))
- lxml.store(id,xmltable)
- stoptiming(xml)
- return xmltable, name or id
-end
-
-function lxml.loaddata(id,str)
- starttiming(xml)
- lxml.nofconverted = lxml.nofconverted + 1
- local xmltable = xml.convert(str or "")
- lxml.store(id,xmltable)
- stoptiming(xml)
- return xmltable, id
-end
-
-function lxml.loadregistered(id)
- return loaded[id], id
-end
-
--- for the moment here:
-
-lxml.set_verbatim("\\xmlcdatabefore", "\\xmlcdataafter", "\\xmlcdataobeyedline", "\\xmlcdataobeyedspace")
-lxml.set_cdata()
-
-local traced = { }
-
-function lxml.trace_text_entities(str)
- return gsub(str,"&(.-);",function(s)
- traced[s] = (traced[s] or 0) + 1
- return "["..s.."]"
- end)
-end
-
-function lxml.show_text_entities()
- for k,v in ipairs(table.sortedkeys(traced)) do
- local h = v:match("^#x(.-)$")
- if h then
- local d = tonumber(h,16)
- local u = utfchar(d)
- logs.report("lxml","entity: %s / %s / %s / n=%s",h,d,u,traced[v])
- else
- logs.report("lxml","entity: %s / n=%s",v,traced[v])
- end
- end
-end
-
-local error_entity_handler = function(s) return format("[%s]",s) end
-local element_entity_handler = function(s) return format("<ctx:e n='%s'/>",s) end
-
-function lxml.set_mkii_entityhandler()
- xml.entity_handler = error_entity_handler
- xml.set_text_cleanup()
-end
-function lxml.set_mkiv_entityhandler()
- xml.entity_handler = element_entity_handler
- xml.set_text_cleanup(xml.resolve_text_entities)
-end
-function lxml.reset_entityhandler()
- xml.entity_handler = error_entity_handler
- xml.set_text_cleanup()
-end
-
-local function with_elements_only(e,handle)
- if e and handle then
- local etg = e.tg
- if etg then
- if e.special and etg ~= "@rt@" then
- if resthandle then
- resthandle(e)
- end
- else
- local edt = e.dt
- if edt then
- for i=1,#edt do
- local e = edt[i]
- if type(e) == "table" then
- handle(e)
- with_elements_only(e,handle)
- end
- end
- end
- end
- end
- end
-end
-
- local function with_elements_only(e,handle,depth)
- if e and handle then
- local edt = e.dt
- if edt then
- depth = depth or 0
- for i=1,#edt do
- local e = edt[i]
- if type(e) == "table" then
- handle(e,depth)
- with_elements_only(e,handle,depth+1)
- end
- end
- end
- end
-end
-
-xml.with_elements_only = with_elements_only
-
-local function to_text(e)
- if e.command == nil then
- local etg = e.tg
- if etg and e.special and etg ~= "@rt@" then
- e.command = false -- i.e. skip
- else
- e.command = true -- i.e. no <self></self>
- end
- end
-end
-local function to_none(e)
- if e.command == nil then
- e.command = false -- i.e. skip
- end
-end
-
--- can be made faster: just recurse over whole table, todo
-
-function lxml.set_command_to_text(id)
- xml.with_elements_only(get_id(id),to_text)
-end
-
-function lxml.set_command_to_none(id)
- xml.with_elements_only(get_id(id),to_none)
-end
-
-function lxml.get_command_status(id)
- local status, stack = {}, {}
- local function get(e,d)
- local ns, tg = e.ns, e.tg
- local name = tg
- if ns ~= "" then name = ns .. ":" .. tg end
- stack[d] = name
- local ec = e.command
- if ec == true then
- ec = "system: text"
- elseif ec == false then
- ec = "system: skip"
- elseif ec == nil then
- ec = "system: not set"
- elseif type(ec) == "string" then
- ec = "setup: " .. ec
- else -- function
- ec = tostring(ec)
- end
- local tag = table.concat(stack," => ",1,d)
- local s = status[tag]
- if not s then
- s = { }
- status[tag] = s
- end
- s[ec] = (s[ec] or 0) + 1
- end
- if id then
- xml.with_elements_only(get_id(id),get)
- return status
- else
- local t = { }
- for id, _ in pairs(loaded) do
- t[id] = lxml.get_command_status(id)
- end
- return t
- end
-end
-
-local setups = { }
-
-function lxml.installsetup(what,document,setup,where)
- document = document or "*"
- local sd = setups[document]
- if not sd then sd = { } setups[document] = sd end
- for k=1,#sd do
- if sd[k] == setup then sd[k] = nil break end
- end
- if what == 1 then
- if trace_loading then
- commands.writestatus("lxml","prepending setup %s for %s",setup,document)
- end
- insert(sd,1,setup)
- elseif what == 2 then
- if trace_loading then
- commands.writestatus("lxml","appending setup %s for %s",setup,document)
- end
- insert(sd,setup)
- elseif what == 3 then
- if trace_loading then
- commands.writestatus("lxml","inserting setup %s for %s before %s",setup,document,where)
- end
- table.insert_before_value(sd,setup,where)
- elseif what == 4 then
- if trace_loading then
- commands.writestatus("lxml","inserting setup %s for %s after %s",setup,document,where)
- end
- table.insert_after_value(sd,setup,where)
- end
-end
-
-function lxml.flushsetups(...)
- local done = { }
- for _, document in ipairs({...}) do
- local sd = setups[document]
- if sd then
- for k=1,#sd do
- local v= sd[k]
- if not done[v] then
- if trace_loading then
- commands.writestatus("lxml","applying setup %02i = %s to %s",k,v,document)
- end
- texsprint(ctxcatcodes,format("\\directsetup{%s}",v))
- done[v] = true
- end
- end
- elseif trace_loading then
- commands.writestatus("lxml","no setups for %s",document)
- end
- end
-end
-
-function lxml.resetsetups(document)
- if trace_loading then
- commands.writestatus("lxml","resetting all setups for %s",document)
- end
- setups[document] = { }
-end
-
-function lxml.removesetup(document,setup)
- local s = setups[document]
- if s then
- for i=1,#s do
- if s[i] == setup then
- if trace_loading then
- commands.writestatus("lxml","removing setup %s for %s",setup,document)
- end
- remove(t,i)
- break
- end
- end
- end
-end
-
--- rather new, indexed storage (backward refs), maybe i will merge this
-
-function lxml.addindex(name,check_sum,force)
- local root = get_id(name)
- if root and (not root.index or force) then -- weird, only called once
- local n, index, maxindex, check = 0, root.index or { }, root.maxindex or 0, root.check or { }
- local function nest(root)
- local dt = root.dt
- if not root.ix then
- maxindex = maxindex + 1
- root.ix = maxindex
- check[maxindex] = root.tg
- index[maxindex] = root
- n = n + 1
- end
- if dt then
- for k=1,#dt do
- local dk = dt[k]
- if type(dk) == "table" then
- nest(dk)
- end
- end
- end
- end
- nest(root)
- lxml.nofindices = lxml.nofindices + n
- --
- if type(name) ~= "string" then
- name = "unknown"
- end
- -- todo: checksum at the end, when tuo saved
---~ if root.checksum then
---~ -- extension mode
---~ root.index = index
---~ root.maxindex = maxindex
---~ commands.writestatus("lxml",format("checksum adapted for %s",tostring(name)))
---~ elseif check_sum then
---~ local tag = format("lxml:%s:checksum",name)
---~ local oldchecksum = jobvariables.collected[tag]
---~ local newchecksum = md5.HEX(concat(check,".")) -- maybe no "." needed
---~ jobvariables.tobesaved[tag] = newchecksum
---~ --
---~ if oldchecksum and oldchecksum ~= "" and oldchecksum ~= newchecksum then
---~ root.index = { }
---~ root.maxindex = 0
---~ root.checksum = newchecksum
---~ commands.writestatus("lxml",format("checksum mismatch for %s (extra run needed)",tostring(name)))
---~ else
---~ root.index = index
---~ root.maxindex = maxindex
---~ root.checksum = newchecksum
---~ commands.writestatus("lxml",format("checksum match for %s: %s",tostring(name),newchecksum))
---~ end
---~ else
- root.index = index
- root.maxindex = maxindex
---~ end
- if trace_access then
- logs.report("lxml","%s indexed, %s nodes",tostring(name),maxindex)
- end
- end
-end
-
--- we can share the index
-
-function lxml.checkindex(name)
- local root = get_id(name)
- return (root and root.index) or 0
-end
-
-function lxml.withindex(name,n,command) -- will change as name is always there now
- local i, p = splitter:match(n)
- if p then
- texsprint(ctxcatcodes,format("\\xmls{%s}{%s}",n,command))
- else
- texsprint(ctxcatcodes,format("\\xmls{%s::%s}{%s}",name,n,command))
- end
-end
-
-function lxml.getindex(name,n) -- will change as name is always there now
- local i, p = splitter:match(n)
- if p then
- texsprint(ctxcatcodes,n)
- else
- texsprint(ctxcatcodes,format("%s::%s",name,n))
- end
-end
-
---
-
-local found, isempty = xml.found, xml.isempty
-
-local doif, doifnot, doifelse = commands.doif, commands.doifnot, commands.doifelse
-
-function lxml.doif (id,pattern) doif (found(get_id(id),pattern,false)) end
-function lxml.doifnot (id,pattern) doifnot (found(get_id(id),pattern,false)) end
-function lxml.doifelse (id,pattern) doifelse(found(get_id(id),pattern,false)) end
-
--- todo: if no second arg or second arg == "" then quick test
-
-function lxml.doiftext (id,pattern) doif (found (get_id(id),pattern,true)) end
-function lxml.doifnottext (id,pattern) doifnot (found (get_id(id),pattern,true)) end
-function lxml.doifelsetext (id,pattern) doifelse(found (get_id(id),pattern,true)) end
-
--- special case: "*" and "" -> self else lpath lookup
-
-function lxml.doifelseempty(id,pattern) doifelse(isempty(get_id(id),pattern ~= "" and pattern ~= nil)) end -- not yet done, pattern
-
--- status info
-
-statistics.register("xml load time", function()
- local noffiles, nofconverted = lxml.noffiles, lxml.nofconverted
- if noffiles > 0 or nofconverted > 0 then
- return format("%s seconds, %s files, %s converted", statistics.elapsedtime(xml), noffiles, nofconverted)
- else
- return nil
- end
-end)
-
---~ statistics.register("lxml preparation time", function()
---~ local n = #lxml.self
---~ if n > 0 then
---~ local stats = xml.statistics()
---~ return format("%s seconds, %s backreferences, %s lpath calls, %s cached calls", statistics.elapsedtime(xml), n, stats.lpathcalls, stats.lpathcached)
---~ else
---~ return nil
---~ end
---~ end)
-
-statistics.register("lxml preparation time", function()
- local noffiles, nofconverted = lxml.noffiles, lxml.nofconverted
- if noffiles > 0 or nofconverted > 0 then
- local stats = xml.statistics()
- return format("%s seconds, %s nodes, %s lpath calls, %s cached calls", statistics.elapsedtime(lxml), lxml.nofindices, stats.lpathcalls, stats.lpathcached)
- else
- return nil
- end
-end)
diff --git a/tex/context/base/lxml-ini.mkiv b/tex/context/base/lxml-ini.mkiv
index 05f89652c..d3a56afbe 100644
--- a/tex/context/base/lxml-ini.mkiv
+++ b/tex/context/base/lxml-ini.mkiv
@@ -15,18 +15,23 @@
\writestatus{loading}{ConTeXt XML Support / Initialization}
-\registerctxluafile{lxml-tab}{1.001}
-\registerctxluafile{lxml-pth}{1.001}
-\registerctxluafile{lxml-ent}{1.001}
-\registerctxluafile{lxml-mis}{1.001}
-\registerctxluafile{lxml-ini}{1.001}
+%registerctxluafile{lxml-tab}{1.001} % loader
+%registerctxluafile{lxml-lpt}{1.001} % parser
+%registerctxluafile{lxml-xml}{1.001} % xml finalizers
+%registerctxluafile{lxml-aux}{1.001} % extras using parser
+%registerctxluafile{lxml-mis}{1.001} % extras independent of parser
+%registerctxluafile{lxml-ent}{1.001} % entity hacks
+\registerctxluafile{lxml-tex}{1.001} % tex finalizers
+\registerctxluafile{lxml-dir}{1.001} % ctx hacks
\unprotect
+\def\c!entities{entities} % to be internationalized
+
\def\xmlmain #1{\ctxlua{lxml.main("#1")}}
\def\xmlall #1#2{\ctxlua{lxml.all("#1","#2")}}
-\def\xmlatt #1#2{\ctxlua{lxml.attribute("#1","/","#2")}}
-\def\xmlattdef #1#2#3{\ctxlua{lxml.attribute("#1","/","#2","#3")}}
+\def\xmlatt #1#2{\ctxlua{lxml.att("#1","#2")}}
+\def\xmlattdef #1#2#3{\ctxlua{lxml.att("#1","#2","#3")}}
\def\xmlchainatt #1#2{\ctxlua{lxml.chainattribute("#1","/","#2")}}
\def\xmlchainattdef #1#2#3{\ctxlua{lxml.chainattribute("#1","/","#2","#3")}}
\def\xmlattribute #1#2#3{\ctxlua{lxml.attribute("#1","#2","#3")}}
@@ -40,6 +45,7 @@
\def\xmldirectivesbefore #1{\ctxlua{lxml.directives.before("#1")}}
\def\xmldirectivesafter #1{\ctxlua{lxml.directives.after("#1")}}
\def\xmlfilter #1#2{\ctxlua{lxml.filter("#1",\!!bs#2\!!es)}}
+\def\xmlfunction #1#2{\ctxlua{lxml["function"]("#1",\!!bs#2\!!es)}}
\def\xmlfirst #1#2{\ctxlua{lxml.first("#1","#2")}}
\def\xmlflush #1{\ctxlua{lxml.flush("#1")}}
%def\xmlcontent #1{\ctxlua{lxml.content("#1")}}
@@ -51,18 +57,12 @@
\def\xmlinfo #1{\hbox{\ttxx[\ctxlua{lxml.info("#1")}]}}
\def\xmlshow #1{\startpacked\ttx\xmlverbatim{#1}\stoppacked}
\def\xmllast #1#2{\ctxlua{lxml.last("#1","#2")}}
-\def\xmlload #1#2{\ctxlua{lxml.load("#1","#2")}}
-\def\xmlloadbuffer #1#2{\ctxlua{lxml.loadbuffer("#1","#2")}}
-\def\xmlloaddata #1#2{\ctxlua{lxml.loaddata("#1",\!!bs#2\!!es)}}
-\def\xmlloadregistered #1#2{\ctxlua{lxml.loadregistered("#1")}}
-\def\xmlloaddirectives #1{\ctxlua{lxml.directives.load("#1")}}
\def\xmlname #1{\ctxlua{lxml.name("#1")}}
\def\xmlnamespace #1{\ctxlua{lxml.namespace("#1")}}
\def\xmlnonspace #1#2{\ctxlua{lxml.nonspace("#1","#2")}}
\def\xmlraw #1#2{\ctxlua{lxml.raw("#1","#2")}}
\def\xmlsnippet #1#2{\ctxlua{lxml.snippet("#1",#2)}}
\def\xmlelement #1#2{\ctxlua{lxml.element("#1",#2)}}
-\def\xmlnofelements #1{\ctxlua{lxml.nofelements("#1")}}
\def\xmlregisterns #1#2{\ctxlua{xml.registerns("#1","#2")}} % document
\def\xmlremapname #1#2#3#4{\ctxlua{xml.remapname(lxml.id("#1"),"#2","#3","#4")}} % element
\def\xmlremapnamespace #1#2#3{\ctxlua{xml.rename_space(lxml.id("#1"),"#2","#3")}} % document
@@ -75,12 +75,17 @@
\def\xmlstrippednolines #1#2{\ctxlua{lxml.stripped("#1","#2",true)}}
\def\xmltag #1{\ctxlua{lxml.tag("#1")}}
\def\xmltext #1#2{\ctxlua{lxml.text("#1","#2")}}
-\def\xmltags #1#2{\ctxlua{lxml.tags("#1","#2")}}
-\def\xmlutfize #1{\ctxlua{lxml.utfize("#1")}}
\def\xmlverbatim #1{\ctxlua{lxml.verbatim("#1")}}
\def\xmldisplayverbatim #1{\ctxlua{lxml.displayverbatim("#1")}}
\def\xmlinlineverbatim #1{\ctxlua{lxml.inlineverbatim("#1")}}
+\def\xmlload #1#2{\ctxlua{lxml.load("#1","#2","\@@xmentities","\@@xmcompress")}}
+\def\xmlloadbuffer #1#2{\ctxlua{lxml.loadbuffer("#1","#2","\@@xmentities","\@@xmcompress")}}
+\def\xmlloaddata #1#2{\ctxlua{lxml.loaddata("#1",\!!bs#2\!!es,"\@@xmentities","\@@xmcompress")}}
+\def\xmlloadregistered #1#2{\ctxlua{lxml.loadregistered("#1","\@@xmentities","\@@xmcompress")}}
+\def\xmlloaddirectives #1{\ctxlua{lxml.directives.load("#1")}}
+\def\xmlpos #1{\ctxlua{lxml.pos("#1")}}
+
%def\xmldoifelse #1#2{\ctxlua{cs.testcase(xml.found(lxml.id("#1"),"#2",false))}}
%def\xmldoifelsetext #1#2{\ctxlua{cs.testcase(xml.found(lxml.id("#1"),"#2",true ))}}
@@ -97,11 +102,9 @@
\def\xmldoiftext #1#2{\ctxlua{lxml.doiftext("#1","#2")}}
\def\xmldoifnottext #1#2{\ctxlua{lxml.doifnottext("#1","#2")}}
\def\xmldoifelsetext #1#2{\ctxlua{lxml.doifelsetext("#1","#2")}}
-\def\xmldoifelseempty #1#2{\ctxlua{lxml.doifelseempty("#1","#2")}} % #2, "*" or "" == self not yet implemented
-\def\xmldoifelseselfempty #1{\ctxlua{lxml.doifelseempty("#1")}}
-\def\xmldefaulttotext #1{\ifcase\xmlprocessingmode\or\or \ctxlua{lxml.set_command_to_text("#1")}\fi}
-\def\xmldefaulttonone #1{\ifcase\xmlprocessingmode\or\or\or\ctxlua{lxml.set_command_to_none("#1")}\fi}
+%def\xmldoifelseempty #1#2{\ctxlua{lxml.doifelseempty("#1","#2")}} % #2, "*" or "" == self not yet implemented
+%def\xmldoifelseselfempty #1{\ctxlua{lxml.doifelseempty("#1")}}
% \startxmlsetups xml:include
% \xmlinclude{main}{include}{filename|href}
@@ -112,11 +115,10 @@
\let\xmlgrab\xmlsetsetup % obsolete
\let\xmlself\s!unknown % obsolete
-\def\xmlsetup#1#2%
- {%\def\xmlself{#1}%
- \setupwithargument{#2}{#1}}
+\def\xmlsetup#1#2{\setupwithargument{#2}{#1}}
\let\xmls\xmlsetup
+\let\xmlw\setupwithargument
\newtoks \registeredxmlsetups
@@ -164,11 +166,7 @@
\edef\xmldocument{#3}% #2 can be \xmldocument and set as such
%xmlpushdocument{#3}%
#2{#3}{#4}%
- \ifcase\xmlprocessingmode
- \enableXML
- \else
- \setcatcodetable\notcatcodes
- \fi
+ \setcatcodetable\notcatcodes
\doifelsenothing{#5}
{\xmlsetup{#3}{xml:process}}
{\xmlsetup{#3}{#5}}%
@@ -198,10 +196,6 @@
% instructions preceding the root element; well, in some
% sense that is the root
-\long\def\xmlloop#1#2#3%
- {\def\xmli##1##2{\xmlidx{#1}{#2/##1}{##2}}%
- \dorecurse{\xmlcount{#1}{#2}}{#3}}
-
\long\def\xmlconnect#1#2#3% inefficient
{\scratchcounter\xmlcount{#1}{#2}\relax
\ifcase\scratchcounter \or
@@ -278,98 +272,43 @@
% setting up xml:
%
-% \setupxml[\c!method=mkii] % mixed mkiv and mkii
-% \setupxml[\c!method=mkiv,\c!default=] % mkiv only
-% \setupxml[\c!method=mkiv,\c!default=\v!none] % mkiv only, undefined -> hidden
-% \setupxml[\c!method=mkiv,\c!default=\v!text] % mkiv only, undefined -> text
+% \setupxml[\c!default=] % mkiv only == text
+% \setupxml[\c!default=\v!none] % mkiv only, undefined -> hidden
+% \setupxml[\c!default=\v!text] % mkiv only, undefined -> text
% \def\xmlctxdirective#1#2#3{\doif{#1}{clue}{\doif{#2}{page}}{\page[#3]}}
-\chardef\xmlprocessingmode=0 % 0=mixed, 1=mkivonly, 2=mkivonly-default-text, 3=mkivonly-default-none
-
-% \setupxml[method=mkiv,strip=yes,entities=yes,default=text]
+\chardef\xmlprocessingmode=0 % 0=unset, 1=text, 2=hidden
\newtoks\everysetupxml
\def\setupxml[#1]{\getparameters[\??xm][#1]\the\everysetupxml}
-\def\c!entities{entities} % to be internationalized
-\def\s!mkiv {mkiv}
-\def\s!mkii {mkii}
-
-% entities
-\newif\ifautoXMLentities
+\letvalue{\??xm:\s!default:\v!normal}\zerocount
+\letvalue{\??xm:\s!default:\v!none }\zerocount
+\letvalue{\??xm:\s!default:\v!text }\plusone
+\letvalue{\??xm:\s!default:\v!hidden}\plustwo
-\def\xmlkeepentities{\ctxlua{lxml.reset_entityhandler()}}
-\def\xmlmkiientities{\ctxlua{lxml.set_mkii_entityhandler()}\autoXMLentitiestrue}
-\def\xmlmkiventities{\ctxlua{lxml.set_mkiv_entityhandler()}}
-
-\let\xmlresolveentities\xmlmkiventities % will become \xmlmkiventities
-
-\letvalue{\??xm:1:\s!mkii }\zerocount
-\letvalue{\??xm:1:\s!mkiv }\plusone
-
-\letvalue{\??xm:2:\v!none }\plusone
-\letvalue{\??xm:2:\v!text }\plustwo
-\letvalue{\??xm:2:\v!hidden}\plusthree
-
-\letvalue{\??xm:ii:\v!yes }\xmlresolveentities
-\letvalue{\??xm:ii:\v!no }\xmlkeepentities
-\letvalue{\??xm:ii:\s!mkii}\xmlmkiientities
-\letvalue{\??xm:ii:\s!mkiv}\xmlmkiventities
-
-\letvalue{\??xm:iv:\v!yes }\xmlresolveentities
-\letvalue{\??xm:iv:\v!no }\xmlkeepentities
-\letvalue{\??xm:iv:\s!mkii}\xmlmkiventities
-\letvalue{\??xm:iv:\s!mkiv}\xmlmkiventities
+\def\xmldefaulttotext#1%
+ {\ifcase\xmlprocessingmode
+ % unset
+ \or
+ \ctxlua{lxml.set_command_to_text("#1")}% 1
+ \or
+ \ctxlua{lxml.set_command_to_none("#1")}% 2
+ \else
+ % unset
+ \fi}
\appendtoks
- \chardef\xmlprocessingmode\executeifdefined{\??xm:1:\@@xmmethod}\zerocount
- \ifcase\xmlprocessingmode
- % mkii, permits both methods
- \executeifdefined{\??xm:ii:\@@xmentities}\xmlkeepentities
- \or
- % mkiv, mkiv exclusively
- \chardef\xmlprocessingmode\executeifdefined{\??xm:2:\@@xmdefault}\plusone
- \executeifdefined{\??xm:iv:\@@xmentities}\xmlresolveentities
- \else
- % unset
- \fi
- \ifcase\xmlprocessingmode
- \ctxlua{characters.setmkiientities()}%
- \else
- \ctxlua{characters.setmkiventities()}%
- \fi
- \doifelse\@@xmcompress\v!yes % this key may change, maybe compress=yes|no
- {\ctxlua{xml.strip_cm_and_dt=true}}
- {\ctxlua{xml.strip_cm_and_dt=false}}%
+ \chardef\xmlprocessingmode\executeifdefined{\??xm:\s!default:\@@xmdefault}\plusone
\to \everysetupxml
\def\xmlinitialize{\the\everysetupxml}
-\newcount\charactersactiveoffset \charactersactiveoffset="10000
-
-\startextendcatcodetable\ctxcatcodes
- \catcode\numexpr\charactersactiveoffset+`<\relax=13
- \catcode\numexpr\charactersactiveoffset+`&\relax=13
- \catcode\numexpr\charactersactiveoffset+`>\relax=13
-\stopextendcatcodetable
-\startextendcatcodetable\xmlcatcodes
- \catcode\numexpr\charactersactiveoffset+`<\relax=13
- \catcode\numexpr\charactersactiveoffset+`&\relax=13
- \catcode\numexpr\charactersactiveoffset+`>\relax=13
-\stopextendcatcodetable
-
-\ctxlua { % entities are remembered in the format
- characters.remapentity("<",characters.active_offset + utf.byte("<"))
- characters.remapentity("&",characters.active_offset + utf.byte("&"))
- characters.remapentity(">",characters.active_offset + utf.byte(">"))
-}
-
\setupxml
- [\c!method=mkii, % mixed mode
- \c!default=\v!hidden, % ignore elements that are not defined
+ [\c!default=, % flush all
\c!compress=\v!no, % strip comment
\c!entities=\v!yes] % replace entities
@@ -391,44 +330,75 @@
%
% mkii: [\processXMLbuffer]\quad mkiv: [\xmlprocessbuffer{main}{}{}]
-% some mkii commands, but mkiv-ified
-
\def\xmlmapvalue#1#2#3{\setvalue{\??xm:v:#1:#2}{#3}} % keep #3 to grab spaces
\def\xmlvalue #1#2#3{\executeifdefined{\??xm:v:#1:#2}{#3}}
\let\xmlmapval\xmlmapvalue
\let\xmlval \xmlvalue
-% brrrr, give this at the top of a style that needs to stub mkiv loading
+%D Experimental:
+
+\def\xmlgetindex #1{\ctxlua{lxml.getindex("\xmldocument","#1")}}
+\def\xmlrawindex #1{\ctxlua{lxml.rawindex("#1")}}
+\def\xmlwithindex #1#2{\ctxlua{lxml.withindex("\xmldocument","#1","#2")}}
+\def\xmlreference #1#2{\string\xmlwithindex{#1}{#2}}
-\def\remapXMLtoMKIV
- {\ifx\xmldocument\undefined\def\xmldocument{main}\fi
- \def\processXMLfile ##1{\xmlprocessfile \xmldocument{##1}{}}%
- \def\processXMLfilegrouped ##1{\xmlprocessfile \xmldocument{##1}{}}% maybe still grouped?
- \def\processXMLbuffer {\dosingleempty\doprocessXMLbuffer}%
- \def\doprocessXMLbuffer [##1]{\xmlprocessbuffer\xmldocument{##1}{}}%
- \def\XMLdata ##1{\xmlprocessdata \xmldocument{##1}{}}%
- \def\startXMLdata##1\stopXMLdata{\xmlprocessdata \xmldocument{##1}{}}}
+%D Entities:
-\let\normalprocessXMLfilegrouped\processXMLfilegrouped
+\chardef\xmlautoentities=1 % 0=off, 1=upper, 2=upper,lower
-\def\processXMLfileMKIV % one-shot, will become obsolete, personal hack
- {\dosingleempty\doprocessXMLfileMKIV}
+\def\xmlsetentity#1#2{\ctxlua{xml.entities['#1'] = \!!bs\detokenize{#2}\!!es}}
-\def\doprocessXMLfileMKIV[#1]%
- {\def\processXMLfilegrouped##1%
- {\let\processXMLfilegrouped\normalprocessXMLfilegrouped
- \doifelsenothing{#1}{\xmlprocess{main}{##1}{}}{\xmlprocess{#1}{##1}{}}}}
+% \xmlsetentity{tex}{\TEX{}} % {} needed
-%D Experimental:
+\unexpanded\def\xmle
+ {\ifcase\xmlautoentities
+ \expandafter\xmle@none
+ \or
+ \expandafter\xmle@upper
+ \or
+ \expandafter\xmle@upperlower
+ \else
+ \expandafter\xmle@none
+ \fi}
-%def\xmlpushdocument#1{\ctxlua{lxml.pushdocument("#1")}}
-%def\xmlpopdocument {\ctxlua{lxml.popdocument()}}
-%def\xmladdindex #1{\ctxlua{lxml.addindex("#1")}}
+\def\xmle@none#1#2% safe
+ {[#1]}
-\def\xmlgetindex #1{\ctxlua{lxml.getindex("\xmldocument","#1")}}
-\def\xmlrawindex #1{\ctxlua{lxml.rawindex("#1")}}
-\def\xmlwithindex #1#2{\ctxlua{lxml.withindex("\xmldocument","#1","#2")}}
-\def\xmlreference #1#2{\string\xmlwithindex{#1}{#2}}
+\def\xmle@upper#1#2% can be abbreviation
+ {\ifcsname#2\endcsname
+ \csname#2\expandafter\endcsname
+ \else
+ [#1]%
+ \fi}
+
+\def\xmle@upperlower#1#2% can be anything, so unsafe
+ {\ifcsname#2\endcsname
+ \csname#2\expandafter\endcsname
+ \else\ifcsname#1\endcsname
+ \csname#1\expandafter\expandafter\expandafter\endcsname
+ \else
+ [#1]%
+ \fi\fi}
\protect \endinput
+
+% \newcount\charactersactiveoffset \charactersactiveoffset="10000
+%
+% \startextendcatcodetable\ctxcatcodes
+% \catcode\numexpr\charactersactiveoffset+`<\relax=13
+% \catcode\numexpr\charactersactiveoffset+`&\relax=13
+% \catcode\numexpr\charactersactiveoffset+`>\relax=13
+% \stopextendcatcodetable
+%
+% \startextendcatcodetable\xmlcatcodes % not needed
+% \catcode\numexpr\charactersactiveoffset+`<\relax=13
+% \catcode\numexpr\charactersactiveoffset+`&\relax=13
+% \catcode\numexpr\charactersactiveoffset+`>\relax=13
+% \stopextendcatcodetable
+%
+% \ctxlua { % entities are remembered in the format
+% characters.remapentity("<",characters.active_offset + utf.byte("<"))
+% characters.remapentity("&",characters.active_offset + utf.byte("&"))
+% characters.remapentity(">",characters.active_offset + utf.byte(">"))
+% }
diff --git a/tex/context/base/lxml-lpt.lua b/tex/context/base/lxml-lpt.lua
new file mode 100644
index 000000000..184d2f1ae
--- /dev/null
+++ b/tex/context/base/lxml-lpt.lua
@@ -0,0 +1,1017 @@
+if not modules then modules = { } end modules ['lxml-pth'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- e.ni is only valid after a filter run
+
+local concat, remove, insert = table.concat, table.remove, table.insert
+local type, next, tonumber, tostring, setmetatable, loadstring = type, next, tonumber, tostring, setmetatable, loadstring
+local format, upper, lower, gmatch, gsub, find, rep = string.format, string.upper, string.lower, string.gmatch, string.gsub, string.find, string.rep
+
+--[[ldx--
+<p>This module can be used stand alone but also inside <l n='mkiv'/> in
+which case it hooks into the tracker code. Therefore we provide a few
+functions that set the tracers. Here we overload a previously defined
+function.</p>
+<p>If I can get in the mood I will make a variant that is XSLT compliant
+but I wonder if it makes sense.</P>
+--ldx]]--
+
+--[[ldx--
+<p>Expecially the lpath code is experimental, we will support some of xpath, but
+only things that make sense for us; as compensation it is possible to hook in your
+own functions. Apart from preprocessing content for <l n='context'/> we also need
+this module for process management, like handling <l n='ctx'/> and <l n='rlx'/>
+files.</p>
+
+<typing>
+a/b/c /*/c
+a/b/c/first() a/b/c/last() a/b/c/index(n) a/b/c/index(-n)
+a/b/c/text() a/b/c/text(1) a/b/c/text(-1) a/b/c/text(n)
+</typing>
+--ldx]]--
+
+local trace_lpath = false if trackers then trackers.register("xml.lpath", function(v) trace_lpath = v end) end
+local trace_lparse = false if trackers then trackers.register("xml.lparse", function(v) trace_lparse = v end) end
+
+--[[ldx--
+<p>We've now arrived at an interesting part: accessing the tree using a subset
+of <l n='xpath'/> and since we're not compatible we call it <l n='lpath'/>. We
+will explain more about its usage in other documents.</p>
+--ldx]]--
+
+local lpathcalls = 0 function xml.lpathcalls () return lpathcalls end
+local lpathcached = 0 function xml.lpathcached() return lpathcached end
+
+xml.functions = xml.functions or { } -- internal
+xml.expressions = xml.expressions or { } -- in expressions
+xml.finalizers = xml.finalizers or { } -- fast do-with ... (with return value other than collection)
+xml.specialhandler = xml.specialhandler or { }
+
+local functions = xml.functions
+local expressions = xml.expressions
+local finalizers = xml.finalizers
+
+finalizers.xml = finalizers.xml or { }
+finalizers.tex = finalizers.tex or { }
+
+local function fallback (t, name)
+ local fn = finalizers[name]
+ if fn then
+ t[name] = fn
+ else
+ logs.report("xml","unknown sub finalizer '%s'",tostring(name))
+ fn = function() end
+ end
+ return fn
+end
+
+setmetatable(finalizers.xml, { __index = fallback })
+setmetatable(finalizers.tex, { __index = fallback })
+
+xml.defaultprotocol = "xml"
+
+-- as xsl does not follow xpath completely here we will also
+-- be more liberal especially with regards to the use of | and
+-- the rootpath:
+--
+-- test : all 'test' under current
+-- /test : 'test' relative to current
+-- a|b|c : set of names
+-- (a|b|c) : idem
+-- ! : not
+--
+-- after all, we're not doing transformations but filtering. in
+-- addition we provide filter functions (last bit)
+--
+-- todo: optimizer
+--
+-- .. : parent
+-- * : all kids
+-- / : anchor here
+-- // : /**/
+-- ** : all in between
+--
+-- so far we had (more practical as we don't transform)
+--
+-- {/test} : kids 'test' under current node
+-- {test} : any kid with tag 'test'
+-- {//test} : same as above
+
+-- evaluator (needs to be redone, for the moment copied)
+
+-- todo: apply_axis(list,notable) and collection vs single
+
+local apply_axis = { }
+
+apply_axis['root'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+ local rt = ll
+ while ll do
+ ll = ll.__p__
+ if ll then
+ rt = ll
+ end
+ end
+ collected[#collected+1] = rt
+ end
+ return collected
+end
+
+apply_axis['self'] = function(list)
+--~ local collected = { }
+--~ for l=1,#list do
+--~ collected[#collected+1] = list[l]
+--~ end
+--~ return collected
+ return list
+end
+
+apply_axis['child'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local dt = list[l].dt
+ for k=1,#dt do
+ local dk = dt[k]
+ if dk.tg then
+ collected[#collected+1] = dk
+ dk.ni = k -- refresh
+ end
+ end
+ end
+ return collected
+end
+
+local function collect(list,collected)
+ local dt = list.dt
+ if dt then
+ for k=1,#dt do
+ local dk = dt[k]
+ if dk.tg then
+ collected[#collected+1] = dk
+ dk.ni = k -- refresh
+ collect(dk,collected)
+ end
+ end
+ end
+end
+apply_axis['descendant'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ collect(list[l],collected)
+ end
+ return collected
+end
+
+local function collect(list,collected)
+ local dt = list.dt
+ if dt then
+ for k=1,#dt do
+ local dk = dt[k]
+ if dk.tg then
+ collected[#collected+1] = dk
+ dk.ni = k -- refresh
+ collect(dk,collected)
+ end
+ end
+ end
+end
+apply_axis['descendant-or-self'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+if ll.special ~= true then -- catch double root
+ collected[#collected+1] = ll
+end
+ collect(ll,collected)
+ end
+ return collected
+end
+
+apply_axis['ancestor'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+ while ll do
+ ll = ll.__p__
+ if ll then
+ collected[#collected+1] = ll
+ end
+ end
+ end
+ return collected
+end
+
+apply_axis['ancestor-or-self'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+ collected[#collected+1] = ll
+ while ll do
+ ll = ll.__p__
+ if ll then
+ collected[#collected+1] = ll
+ end
+ end
+ end
+ return collected
+end
+
+apply_axis['parent'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local pl = list[l].__p__
+ if pl then
+ collected[#collected+1] = pl
+ end
+ end
+ return collected
+end
+
+apply_axis['attribute'] = function(list)
+ return { }
+end
+
+apply_axis['following'] = function(list)
+ return { }
+end
+
+apply_axis['following-sibling'] = function(list)
+ return { }
+end
+
+apply_axis['namespace'] = function(list)
+ return { }
+end
+
+apply_axis['preceding'] = function(list)
+ return { }
+end
+
+apply_axis['preceding-sibling'] = function(list)
+ return { }
+end
+
+apply_axis['auto-descendant-or-self'] = apply_axis['descendant-or-self']
+apply_axis['auto-descendant'] = apply_axis['descendant']
+apply_axis['auto-child'] = apply_axis['child']
+apply_axis['auto-self'] = apply_axis['self']
+apply_axis['initial-child'] = apply_axis['child']
+
+local function apply_nodes(list,directive,nodes)
+ -- todo: nodes[1] etc ... negated node name in set ... when needed
+ -- ... currently ignored
+ local maxn = #nodes
+ if maxn == 3 then --optimized loop
+ local nns, ntg = nodes[2], nodes[3]
+ if not nns and not ntg then -- wildcard
+ if directive then
+ return list
+ else
+ return { }
+ end
+ else
+ local collected = { }
+ if not nns then -- only check tag
+ for l=1,#list do
+ local ll = list[l]
+ local ltg = ll.tg
+ if ltg then
+ if directive then
+ if ntg == ltg then
+ collected[#collected+1] = ll
+ end
+ elseif ntg ~= ltg then
+ collected[#collected+1] = ll
+ end
+ end
+ end
+ elseif not ntg then -- only check namespace
+ for l=1,#list do
+ local ll = list[l]
+ local lns = ll.rn or ll.ns
+ if lns then
+ if directive then
+ if lns == nns then
+ collected[#collected+1] = ll
+ end
+ elseif lns ~= nns then
+ collected[#collected+1] = ll
+ end
+ end
+ end
+ else -- check both
+ for l=1,#list do
+ local ll = list[l]
+ local ltg = ll.tg
+ if ltg then
+ local lns = ll.rn or ll.ns
+ local ok = ltg == ntg and lns == nns
+ if directive then
+ if ok then
+ collected[#collected+1] = ll
+ end
+ elseif not ok then
+ collected[#collected+1] = ll
+ end
+ end
+ end
+ end
+ return collected
+ end
+ else
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+ local ltg = ll.tg
+ if ltg then
+ local lns = ll.rn or ll.ns
+ local ok = false
+ for n=1,maxn,3 do
+ local nns, ntg = nodes[n+1], nodes[n+2]
+ ok = (not ntg or ltg == ntg) and (not nns or lns == nns)
+ if ok then
+ break
+ end
+ end
+ if directive then
+ if ok then
+ collected[#collected+1] = ll
+ end
+ elseif not ok then
+ collected[#collected+1] = ll
+ end
+ end
+ end
+ return collected
+ end
+end
+
+local function apply_expression(list,expression,order)
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+ if expression(list,ll,l,order) then -- nasty, alleen valid als n=1
+ collected[#collected+1] = ll
+ end
+ end
+ return collected
+end
+
+local P, V, C, Cs, Cc, Ct, R, S, Cg, Cb = lpeg.P, lpeg.V, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.Ct, lpeg.R, lpeg.S, lpeg.Cg, lpeg.Cb
+
+local spaces = S(" \n\r\t\f")^0
+
+local lp_space = S(" \n\r\t\f")
+local lp_any = P(1)
+
+local lp_noequal = P("!=") / "~=" + P("<=") + P(">=") + P("==")
+local lp_doequal = P("=") / "=="
+local lp_or = P("|") / " or "
+local lp_and = P("&") / " and "
+
+local lp_builtin = P (
+ P("first") / "1" +
+ P("last") / "#list" +
+ P("position") / "l" +
+ P("rootposition") / "order" +
+ P("index") / "ll.ni" +
+ P("text") / "(ll.dt[1] or '')" +
+ P("name") / "(ll.ns~='' and ll.ns..':'..ll.tg)" +
+ P("tag") / "ll.tg" +
+ P("ns") / "ll.ns"
+ ) * ((spaces * P("(") * spaces * P(")"))/"")
+
+local lp_attribute = (P("@") + P("attribute::")) / "" * Cc("ll.at['") * R("az","AZ","--","__")^1 * Cc("']")
+local lp_fastpos = ((R("09","--","++")^1 * P(-1)) / function(s) return "l==" .. s end)
+
+local lp_reserved = C("and") + C("or") + C("not") + C("div") + C("mod") + C("true") + C("false")
+
+local lp_lua_function = C(R("az","AZ","__")^1 * (P(".") * R("az","AZ","__")^1)^1) * ("(") / function(t) -- todo: better . handling
+ return t .. "("
+end
+
+local lp_function = C(R("az","AZ","__")^1) * P("(") / function(t) -- todo: better . handling
+ if expressions[t] then
+ return "expr." .. t .. "("
+ else
+ return "expr.error("
+ end
+end
+
+local lparent = lpeg.P("(")
+local rparent = lpeg.P(")")
+local noparent = 1 - (lparent+rparent)
+local nested = lpeg.P{lparent * (noparent + lpeg.V(1))^0 * rparent}
+local value = lpeg.P(lparent * lpeg.C((noparent + nested)^0) * rparent) -- lpeg.P{"("*C(((1-S("()"))+V(1))^0)*")"}
+
+local lp_child = Cc("expr.child(e,'") * R("az","AZ","--","__")^1 * Cc("')")
+local lp_string = Cc("'") * R("az","AZ","--","__")^1 * Cc("'")
+local lp_content= (P("'") * (1-P("'"))^0 * P("'") + P('"') * (1-P('"'))^0 * P('"'))
+
+local cleaner
+
+local lp_special = (C(P("name")+P("text")+P("tag")+P("count")+P("child"))) * value / function(t,s)
+ if expressions[t] then
+ s = s and s ~= "" and cleaner:match(s)
+ if s and s ~= "" then
+ return "expr." .. t .. "(e," .. s ..")"
+ else
+ return "expr." .. t .. "(e)"
+ end
+ else
+ return "expr.error(" .. t .. ")"
+ end
+end
+
+local content =
+ lp_builtin +
+ lp_attribute +
+ lp_special +
+ lp_noequal + lp_doequal +
+ lp_or + lp_and +
+ lp_reserved +
+ lp_lua_function + lp_function +
+ lp_content + -- too fragile
+ lp_child +
+ lp_any
+
+local converter = lpeg.Cs (
+ lp_fastpos + (lpeg.P { lparent * (lpeg.V(1))^0 * rparent + content } )^0
+)
+
+cleaner = lpeg.Cs ( (
+--~ lp_fastpos +
+ lp_reserved +
+ lp_string +
+1 )^1 )
+
+--~ expr
+
+local template_e = [[
+ local expr = xml.expressions
+ return function(list,ll,l,root)
+ return %s
+ end
+]]
+
+local template_f_y = [[
+ local finalizer = xml.finalizers['%s']['%s']
+ return function(collection)
+ return finalizer(collection,%s)
+ end
+]]
+
+local template_f_n = [[
+ return xml.finalizers['%s']['%s']
+]]
+
+--
+
+local function errorrunner_e(str,cnv)
+ logs.report("lpath","error in expression: %s => %s",str,cnv)
+ return false
+end
+local function errorrunner_f(str,arg)
+ logs.report("lpath","error in finalizer: %s(%s)",str,arg or "")
+ return false
+end
+
+local function register_nodes(nodetest,nodes)
+ return { kind = "nodes", nodetest = nodetest, nodes = nodes }
+end
+
+local function register_expression(expression)
+ local converted = converter:match(expression)
+ local runner = loadstring(format(template_e,converted))
+ runner = (runner and runner()) or function() errorrunner_e(expression,converted) end
+ return { kind = "expression", expression = expression, converted = converted, evaluator = runner }
+end
+
+local function register_finalizer(protocol,name,arguments)
+ local runner
+ if arguments and arguments ~= "" then
+ runner = loadstring(format(template_f_y,protocol or xml.defaultprotocol,name,arguments))
+ else
+ runner = loadstring(format(template_f_n,protocol or xml.defaultprotocol,name))
+ end
+ runner = (runner and runner()) or function() errorrunner_f(name,arguments) end
+ return { kind = "finalizer", name = name, arguments = arguments, finalizer = runner }
+end
+
+local expression = P { "ex",
+ ex = "[" * C((V("sq") + V("dq") + (1 - S("[]")) + V("ex"))^0) * "]",
+ sq = "'" * (1 - S("'"))^0 * "'",
+ dq = '"' * (1 - S('"'))^0 * '"',
+}
+
+local arguments = P { "ar",
+ ar = "(" * Cs((V("sq") + V("dq") + V("nq") + P(1-P(")")))^0) * ")",
+ nq = ((1 - S("),'\""))^1) / function(s) return format("%q",s) end,
+ sq = P("'") * (1 - P("'"))^0 * P("'"),
+ dq = P('"') * (1 - P('"'))^0 * P('"'),
+}
+
+-- todo: better arg parser
+
+local register_self = { kind = "axis", axis = "self" } -- , apply = apply_axis["self"] }
+local register_parent = { kind = "axis", axis = "parent" } -- , apply = apply_axis["parent"] }
+local register_descendant = { kind = "axis", axis = "descendant" } -- , apply = apply_axis["descendant"] }
+local register_child = { kind = "axis", axis = "child" } -- , apply = apply_axis["child"] }
+local register_descendant_or_self = { kind = "axis", axis = "descendant-or-self" } -- , apply = apply_axis["descendant-or-self"] }
+local register_root = { kind = "axis", axis = "root" } -- , apply = apply_axis["root"] }
+local register_ancestor = { kind = "axis", axis = "ancestor" } -- , apply = apply_axis["ancestor"] }
+local register_ancestor_or_self = { kind = "axis", axis = "ancestor-or-self" } -- , apply = apply_axis["ancestor-or-self"] }
+local register_attribute = { kind = "axis", axis = "attribute" } -- , apply = apply_axis["attribute"] }
+local register_namespace = { kind = "axis", axis = "namespace" } -- , apply = apply_axis["namespace"] }
+local register_following = { kind = "axis", axis = "following" } -- , apply = apply_axis["following"] }
+local register_following_sibling = { kind = "axis", axis = "following-sibling" } -- , apply = apply_axis["following-sibling"] }
+local register_preceding = { kind = "axis", axis = "preceding" } -- , apply = apply_axis["preceding"] }
+local register_preceding_sibling = { kind = "axis", axis = "preceding-sibling" } -- , apply = apply_axis["preceding-sibling"] }
+
+local register_auto_descendant_or_self = { kind = "axis", axis = "auto-descendant-or-self" } -- , apply = apply_axis["auto-descendant-or-self"] }
+local register_auto_descendant = { kind = "axis", axis = "auto-descendant" } -- , apply = apply_axis["auto-descendant"] }
+local register_auto_self = { kind = "axis", axis = "auto-self" } -- , apply = apply_axis["auto-self"] }
+local register_auto_child = { kind = "axis", axis = "auto-child" } -- , apply = apply_axis["auto-child"] }
+
+local register_initial_child = { kind = "axis", axis = "initial-child" } -- , apply = apply_axis["initial-child"] }
+
+local register_all_nodes = { kind = "nodes", nodetest = true, nodes = { true, false, false } }
+
+local function register_error(str)
+ return { kind = "error", comment = format("unparsed: %s",str) }
+end
+
+local parser = Ct { "patterns", -- can be made a bit faster by moving pattern outside
+
+ patterns = spaces * V("protocol") * spaces * V("initial") * spaces * V("step") * spaces *
+ (P("/") * spaces * V("step") * spaces)^0,
+
+ protocol = Cg(V("letters"),"protocol") * P("://") + Cg(Cc(nil),"protocol"),
+
+ step = (V("shortcuts") + V("axis") * spaces * V("nodes")^0 + V("error")) * spaces * V("expressions")^0 * spaces * V("finalizer")^0,
+
+ axis = V("descendant") + V("child") + V("parent") + V("self") + V("root") + V("ancestor") +
+ V("descendant_or_self") + V("following") + V("following_sibling") +
+ V("preceding") + V("preceding_sibling") + V("ancestor_or_self") +
+ #(1-P(-1)) * Cc(register_auto_child),
+
+ initial = (P("/") * spaces * Cc(register_initial_child))^-1,
+
+ error = (P(1)^1) / register_error,
+
+ shortcuts_a = V("s_descendant_or_self") + V("s_descendant") + V("s_child") + V("s_parent") + V("s_self") + V("s_root") + V("s_ancestor"),
+
+ shortcuts = V("shortcuts_a") * (spaces * "/" * spaces * V("shortcuts_a"))^0,
+
+ s_descendant_or_self = P("/") * Cc(register_descendant_or_self),
+ s_descendant = P("**") * Cc(register_descendant),
+ s_child = P("*") * Cc(register_child ),
+ s_parent = P("..") * Cc(register_parent ),
+ s_self = P("." ) * Cc(register_self ),
+ s_root = P("^^") * Cc(register_root ),
+ s_ancestor = P("^") * Cc(register_ancestor ),
+
+ descendant = P("descendant::") * Cc(register_descendant ),
+ child = P("child::") * Cc(register_child ),
+ parent = P("parent::") * Cc(register_parent ),
+ self = P("self::") * Cc(register_self ),
+ root = P('root::') * Cc(register_root ),
+ ancestor = P('ancestor::') * Cc(register_ancestor ),
+ descendant_or_self = P('descendant-or-self::') * Cc(register_descendant_or_self ),
+ ancestor_or_self = P('ancestor-or-self::') * Cc(register_ancestor_or_self ),
+ -- attribute = P('attribute::') * Cc(register_attribute ),
+ -- namespace = P('namespace::') * Cc(register_namespace ),
+ following = P('following::') * Cc(register_following ),
+ following_sibling = P('following-sibling::') * Cc(register_following_sibling ),
+ preceding = P('preceding::') * Cc(register_preceding ),
+ preceding_sibling = P('preceding-sibling::') * Cc(register_preceding_sibling ),
+
+ nodes = (V("nodefunction") * spaces * P("(") * V("nodeset") * P(")") + V("nodetest") * V("nodeset")) / register_nodes,
+
+ expressions = expression / register_expression,
+
+ letters = R("az")^1,
+ name = (1-lpeg.S("/[]()|:*!"))^1,
+ negate = P("!") * Cc(false),
+
+ nodefunction = V("negate") + P("not") * Cc(false) + Cc(true),
+ nodetest = V("negate") + Cc(true),
+ nodename = (V("negate") + Cc(true)) * spaces * ((V("wildnodename") * P(":") * V("wildnodename")) + (Cc(false) * V("wildnodename"))),
+ wildnodename = (C(V("name")) + P("*") * Cc(false)) * #(1-P("(")),
+ nodeset = spaces * Ct(V("nodename") * (spaces * P("|") * spaces * V("nodename"))^0) * spaces,
+
+ finalizer = (Cb("protocol") * P("/")^-1 * C(V("name")) * arguments * P(-1)) / register_finalizer,
+
+}
+
+local cache = { }
+
+local function nodesettostring(set,nodetest)
+ local t = { }
+ for i=1,#set,3 do
+ local directive, ns, tg = set[i], set[i+1], set[i+2]
+ if not ns or ns == "" then ns = "*" end
+ if not tg or tg == "" then tg = "*" end
+ tg = (tg == "@rt@" and "[root]") or format("%s:%s",ns,tg)
+ t[#t+1] = (directive and tg) or format("not(%s)",tg)
+ end
+ if nodetest == false then
+ return format("not(%s)",concat(t,"|"))
+ else
+ return concat(t,"|")
+ end
+end
+
+local function tagstostring(list)
+ if #list == 0 then
+ return "no elements"
+ else
+ local t = { }
+ for i=1, #list do
+ local li = list[i]
+ local ns, tg = li.ns, li.tg
+ if not ns or ns == "" then ns = "*" end
+ if not tg or tg == "" then tg = "*" end
+ t[#t+1] = (tg == "@rt@" and "[root]") or format("%s:%s",ns,tg)
+ end
+ return concat(t," ")
+ end
+end
+
+xml.nodesettostring = nodesettostring
+
+local function lshow(parsed)
+ if type(parsed) == "string" then
+ parsed = parse_pattern(parsed)
+ end
+ local s = table.serialize_functions -- ugly
+ table.serialize_functions = false -- ugly
+ logs.report("lpath","%s://%s => %s",parsed.protocol or xml.defaultprotocol,parsed.pattern,table.serialize(parsed,false))
+ table.serialize_functions = s -- ugly
+end
+
+xml.lshow = lshow
+
+local function parse_pattern(pattern) -- the gain of caching is rather minimal
+ lpathcalls = lpathcalls + 1
+ if type(pattern) == "table" then
+ return pattern
+ else
+ local parsed = cache[pattern]
+ if parsed then
+ lpathcached = lpathcached + 1
+ else
+ parsed = parser:match(pattern)
+ if parsed then
+ parsed.pattern = pattern
+ local np = #parsed
+ if np == 0 then
+ parsed = { pattern = pattern, register_self, state = "parsing error" }
+ logs.report("lpath","parsing error in '%s'",pattern)
+ lshow(parsed)
+ else
+ -- we could have done this with a more complex parsed but this
+ -- is cleaner
+ local pi = parsed[1]
+ if pi.axis == "auto-child" then
+ parsed.comment = "auto-child replaced by auto-descendant-or-self"
+ parsed[1] = register_auto_descendant_or_self
+ --~ parsed.comment = "auto-child replaced by auto-descendant"
+ --~ parsed[1] = register_auto_descendant
+ elseif pi.axis == "initial-child" and np > 1 and parsed[2].axis then
+ parsed.comment = "initial-child removed" -- we could also make it a auto-self
+ remove(parsed,1)
+ end
+ end
+ else
+ parsed = { pattern = pattern }
+ end
+ cache[pattern] = parsed
+ if trace_lparse then
+ lshow(parsed)
+ end
+ end
+ return parsed
+ end
+end
+
+-- we can move all calls inline and then merge the trace back
+-- technically we can combine axis and the next nodes which is
+-- what we did before but this a bit cleaner (but slower too)
+-- but interesting is that it's not that much faster when we
+-- go inline
+--
+-- beware: we need to return a collection even when we filter
+-- else the (simple) cache gets messed up
+
+-- caching found lookups saves not that much (max .1 sec on a 8 sec run)
+-- and it also messes up finalizers
+
+local function parse_apply(list,pattern)
+ -- we avoid an extra call
+ local parsed = cache[pattern]
+ if parsed then
+ lpathcalls = lpathcalls + 1
+ lpathcached = lpathcached + 1
+ elseif type(pattern) == "table" then
+ lpathcalls = lpathcalls + 1
+ parsed = pattern
+ else
+ parsed = parse_pattern(pattern) or pattern
+ end
+ if not parsed then
+ return
+ end
+ local nofparsed = #parsed
+ if nofparsed > 0 then
+ if trace_lpath then
+ if trace_lparse then
+ lshow(parsed)
+ end
+ logs.report("lpath", "collecting : %s",pattern)
+ logs.report("lpath", " root tags : %s",tagstostring(list))
+ local collected = list
+ for i=1,nofparsed do
+ local pi = parsed[i]
+ local kind = pi.kind
+ if kind == "axis" then
+ collected = apply_axis[pi.axis](collected)
+ -- collected = pi.apply(collected)
+ logs.report("lpath", "% 10i : ax : %s",(collected and #collected) or 0,pi.axis)
+ elseif kind == "nodes" then
+ collected = apply_nodes(collected,pi.nodetest,pi.nodes)
+ logs.report("lpath", "% 10i : ns : %s",(collected and #collected) or 0,nodesettostring(pi.nodes,pi.nodetest))
+ elseif kind == "expression" then
+ collected = apply_expression(collected,pi.evaluator,i)
+ logs.report("lpath", "% 10i : ex : %s",(collected and #collected) or 0,pi.expression)
+ elseif kind == "finalizer" then
+ collected = pi.finalizer(collected)
+ logs.report("lpath", "% 10i : fi : %s : %s(%s)",(collected and #collected) or 0,parsed.protocol or xml.defaultprotocol,pi.name,pi.arguments or "")
+ return collected
+ end
+ if not collected or #collected == 0 then
+ return nil
+ end
+ end
+ return collected
+ else
+ local collected = list
+ for i=1,nofparsed do
+ local pi = parsed[i]
+ local kind = pi.kind
+ if kind == "axis" then
+ local axis = pi.axis
+ if axis ~= "self" then
+ collected = apply_axis[axis](collected)
+ end
+ elseif kind == "nodes" then
+ collected = apply_nodes(collected,pi.nodetest,pi.nodes)
+ elseif kind == "expression" then
+ collected = apply_expression(collected,pi.evaluator,i)
+ elseif kind == "finalizer" then
+ return pi.finalizer(collected)
+ end
+ if not collected or #collected == 0 then
+ return nil
+ end
+ end
+ return collected
+ end
+ end
+end
+
+-- internal (parsed)
+
+expressions.child = function(e,pattern)
+ return parse_apply({ e },pattern) -- todo: cache
+end
+expressions.count = function(e,pattern)
+ local collected = parse_apply({ e },pattern) -- todo: cache
+ return (collected and #collected) or 0
+end
+
+-- external
+
+expressions.oneof = function(s,...) -- slow
+ local t = {...} for i=1,#t do if s == t[i] then return true end end return false
+end
+expressions.error = function(str)
+ xml.error_handler("unknown function in lpath expression",tostring(str or "?"))
+ return false
+end
+expressions.undefined = function(s)
+ return s == nil
+end
+
+expressions.contains = find
+expressions.find = find
+expressions.upper = upper
+expressions.lower = lower
+expressions.number = tonumber
+expressions.boolean = toboolean
+
+-- user interface
+
+local function traverse(root,pattern,handle)
+ logs.report("xml","use 'xml.selection' instead for '%s'",pattern)
+ local collected = parse_apply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ local r = e.__p__
+ handle(r,r.dt,e.ni)
+ end
+ end
+end
+
+local function selection(root,pattern,handle)
+ local collected = parse_apply({ root },pattern)
+ if collected then
+ if handle then
+ for c=1,#collected do
+ handle(collected[c])
+ end
+ else
+ return collected
+ end
+ end
+end
+
+xml.parse_parser = parser
+xml.parse_pattern = parse_pattern
+xml.parse_apply = parse_apply
+xml.traverse = traverse -- old method, r, d, k
+xml.selection = selection -- new method, simple handle
+
+local lpath = parse_pattern
+
+xml.lpath = lpath
+
+function xml.cached_patterns()
+ return cache
+end
+
+-- generic function finalizer (independant namespace)
+
+local function dofunction(collected,fnc)
+ if collected then
+ local f = functions[fnc]
+ if f then
+ for c=1,#collected do
+ f(collected[c])
+ end
+ else
+ logs.report("xml","unknown function '%s'",fnc)
+ end
+ end
+end
+
+xml.finalizers.xml["function"] = dofunction
+xml.finalizers.tex["function"] = dofunction
+
+-- functions
+
+expressions.text = function(e,n)
+ local rdt = e.__p__.dt
+ return (rdt and rdt[n]) or ""
+end
+
+expressions.name = function(e,n) -- ns + tg
+ local found = false
+ n = tonumber(n) or 0
+ if n == 0 then
+ found = type(e) == "table" and e
+ elseif n < 0 then
+ local d, k = e.__p__.dt, e.ni
+ for i=k-1,1,-1 do
+ local di = d[i]
+ if type(di) == "table" then
+ if n == -1 then
+ found = di
+ break
+ else
+ n = n + 1
+ end
+ end
+ end
+ else
+ local d, k = e.__p__.dt, e.ni
+ for i=k+1,#d,1 do
+ local di = d[i]
+ if type(di) == "table" then
+ if n == 1 then
+ found = di
+ break
+ else
+ n = n - 1
+ end
+ end
+ end
+ end
+ if found then
+ local ns, tg = found.rn or found.ns or "", found.tg
+ if ns ~= "" then
+ return ns .. ":" .. tg
+ else
+ return tg
+ end
+ else
+ return ""
+ end
+end
+
+expressions.tag = function(e,n) -- only tg
+ local found = false
+ n = tonumber(n) or 0
+ if n == 0 then
+ found = (type(e) == "table") and e -- seems to fail
+ elseif n < 0 then
+ local d, k = e.__p__.dt, e.ni
+ for i=k-1,1,-1 do
+ local di = d[i]
+ if type(di) == "table" then
+ if n == -1 then
+ found = di
+ break
+ else
+ n = n + 1
+ end
+ end
+ end
+ else
+ local d, k = e.__p__.dt, e.ni
+ for i=k+1,#d,1 do
+ local di = d[i]
+ if type(di) == "table" then
+ if n == 1 then
+ found = di
+ break
+ else
+ n = n - 1
+ end
+ end
+ end
+ end
+ return (found and found.tg) or ""
+end
+
+--[[ldx--
+<p>This is the main filter function. It returns whatever is asked for.</p>
+--ldx]]--
+
+function xml.filter(root,pattern) -- no longer funny attribute handling here
+ return parse_apply({ root },pattern)
+end
+
+--[[ldx--
+<p>Often using an iterators looks nicer in the code than passing handler
+functions. The <l n='lua'/> book describes how to use coroutines for that
+purpose (<url href='http://www.lua.org/pil/9.3.html'/>). This permits
+code like:</p>
+
+<typing>
+for r, d, k in xml.elements(xml.load('text.xml'),"title") do
+ print(d[k]) -- old method
+end
+for e in xml.collected(xml.load('text.xml'),"title") do
+ print(e) -- new one
+end
+</typing>
+--ldx]]--
+
+local wrap, yield = coroutine.wrap, coroutine.yield
+
+function xml.elements(root,pattern,reverse) -- r, d, k
+ local collected = parse_apply({ root },pattern)
+ if collected then
+ if reverse then
+ return wrap(function() for c=#collected,1,-1 do
+ local e = collected[c] local r = e.__p__ yield(r,r.dt,e.ni)
+ end end)
+ else
+ return wrap(function() for c=1,#collected do
+ local e = collected[c] local r = e.__p__ yield(r,r.dt,e.ni)
+ end end)
+ end
+ end
+ return wrap(function() end)
+end
+
+function xml.collected(root,pattern,reverse) -- e
+ local collected = parse_apply({ root },pattern)
+ if collected then
+ if reverse then
+ return wrap(function() for c=#collected,1,-1 do yield(collected[c]) end end)
+ else
+ return wrap(function() for c=1,#collected do yield(collected[c]) end end)
+ end
+ end
+ return wrap(function() end)
+end
diff --git a/tex/context/base/lxml-mis.lua b/tex/context/base/lxml-mis.lua
index a117b1af9..eff012013 100644
--- a/tex/context/base/lxml-mis.lua
+++ b/tex/context/base/lxml-mis.lua
@@ -18,7 +18,8 @@ this module. Since this module is also used in <l n='mtxrun'/> we've
put them here instead of loading mode modules there then needed.</p>
--ldx]]--
-function xml.gsub(t,old,new)
+
+local function xmlgsub(t,old,new)
local dt = t.dt
if dt then
for k=1,#dt do
@@ -26,26 +27,24 @@ function xml.gsub(t,old,new)
if type(v) == "string" then
dt[k] = gsub(v,old,new)
else
- xml.gsub(v,old,new)
+ xmlgsub(v,old,new)
end
end
end
end
+xmlgsub = xmlgsub
+
function xml.strip_leading_spaces(dk,d,k) -- cosmetic, for manual
- if d and k and d[k-1] and type(d[k-1]) == "string" then
- local s = d[k-1]:match("\n(%s+)")
- xml.gsub(dk,"\n"..string.rep(" ",#s),"\n")
+ if d and k then
+ local dkm = d[k-1]
+ if dkm and type(dkm) == "string" then
+ local s = match(dkm,"\n(%s+)")
+ xmlgsub(dk,"\n"..rep(" ",#s),"\n")
+ end
end
end
-function xml.serialize_path(root,lpath,handle)
- local dk, r, d, k = xml.first(root,lpath)
- dk = xml.copy(dk)
- xml.strip_leading_spaces(dk,d,k)
- 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
@@ -71,8 +70,6 @@ local escaped = Cs(normal * (special * normal)^0)
-- 100 * 1000 * "oeps&lt; oeps&gt; oeps&amp;" : gsub:lpeg == 0153:0280:0151:0080 (last one by roberto)
--- unescaped = Cs((S("&lt;")/"<" + S("&gt;")/">" + S("&amp;")/"&" + 1)^0)
--- unescaped = Cs((((P("&")/"") * (P("lt")/"<" + P("gt")/">" + P("amp")/"&") * (P(";")/"")) + 1)^0)
local normal = (1 - S"&")^0
local special = P("&lt;")/"<" + P("&gt;")/">" + P("&amp;")/"&"
local unescaped = Cs(normal * (special * normal)^0)
@@ -88,19 +85,3 @@ xml.cleansed_pattern = cleansed
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
-
-function xml.join(t,separator,lastseparator)
- if #t > 0 then
- local result = { }
- for k,v in pairs(t) do
- result[k] = xml.tostring(v)
- end
- if lastseparator then
- return concat(result,separator or "",1,#result-1) .. (lastseparator or "") .. result[#result]
- else
- return concat(result,separator)
- end
- else
- return ""
- end
-end
diff --git a/tex/context/base/lxml-pth.lua b/tex/context/base/lxml-pth.lua
deleted file mode 100644
index a1bebe017..000000000
--- a/tex/context/base/lxml-pth.lua
+++ /dev/null
@@ -1,1735 +0,0 @@
-if not modules then modules = { } end modules ['lxml-pth'] = {
- version = 1.001,
- comment = "this module is the basis for the lxml-* ones",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local concat, remove, insert = table.concat, table.remove, table.insert
-local type, next, tonumber, tostring, setmetatable, loadstring = type, next, tonumber, tostring, setmetatable, loadstring
-local format, lower, gmatch, gsub, find, rep = string.format, string.lower, string.gmatch, string.gsub, string.find, string.rep
-
---[[ldx--
-<p>This module can be used stand alone but also inside <l n='mkiv'/> in
-which case it hooks into the tracker code. Therefore we provide a few
-functions that set the tracers. Here we overload a previously defined
-function.</p>
-<p>If I can get in the mood I will make a variant that is XSLT compliant
-but I wonder if it makes sense.</P>
---ldx]]--
-
-local trace_lpath = false if trackers then trackers.register("xml.lpath", function(v) trace_lpath = v end) end
-
-local settrace = xml.settrace -- lxml-tab
-
-function xml.settrace(str,value)
- if str == "lpath" then
- trace_lpath = value or false
- else
- settrace(str,value) -- lxml-tab
- end
-end
-
---[[ldx--
-<p>We've now arrived at an intersting part: accessing the tree using a subset
-of <l n='xpath'/> and since we're not compatible we call it <l n='lpath'/>. We
-will explain more about its usage in other documents.</p>
---ldx]]--
-
-local lpathcalls = 0 -- statistics
-local lpathcached = 0 -- statistics
-
-xml.functions = xml.functions or { }
-xml.expressions = xml.expressions or { }
-
-local functions = xml.functions
-local expressions = xml.expressions
-
--- although we could remap all to expressions we prefer to have a few speed ups
--- like simple expressions as they happen to occur a lot and then we want to
--- avoid too many loops
-
-local actions = {
- [10] = "stay",
- [11] = "parent",
- [12] = "subtree root",
- [13] = "document root",
- [14] = "any",
- [15] = "many",
- [16] = "initial",
- [20] = "match",
- [21] = "match one of",
- [22] = "match and attribute eq",
- [23] = "match and attribute ne",
- [24] = "match one of and attribute eq",
- [25] = "match one of and attribute ne",
- [26] = "has name",
- [27] = "has attribute",
- [28] = "has value",
- [29] = "fast match",
- [30] = "select",
- [31] = "expression",
- [40] = "processing instruction",
-}
-
--- a rather dumb lpeg
-
-local P, S, R, C, V, Cc = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc
-
--- instead of using functions we just parse a few names which saves a call
--- later on
---
--- we can use a metatable
-
-local lp_space = S(" \n\r\t")
-local lp_any = P(1)
-local lp_position = P("position()") / "ps"
-local lp_index = P("index()") / "id"
-local lp_text = P("text()") / "tx"
-local lp_name = P("name()") / "(ns~='' and ns..':'..tg)" -- "((rt.ns~='' and rt.ns..':'..rt.tg) or '')"
-local lp_tag = P("tag()") / "tg" -- (rt.tg or '')
-local lp_ns = P("ns()") / "ns" -- (rt.ns or '')
-local lp_noequal = P("!=") / "~=" + P("<=") + P(">=") + P("==")
-local lp_doequal = P("=") / "=="
---~ local lp_attribute = P("@") / "" * Cc("(at['") * R("az","AZ","--","__")^1 * Cc("'] or '')")
-local lp_attribute = P("@") / "" * Cc("at['") * R("az","AZ","--","__")^1 * Cc("']")
-local lp_or = P("|") / " or "
-local lp_and = P("&") / " and "
-
-local lp_reserved = C("and") + C("or") + C("not") + C("div") + C("mod") + C("true") + C("false")
-
-local lp_lua_function = C(R("az","AZ","--","__")^1 * (P(".") * R("az","AZ","--","__")^1)^1) * P("(") / function(t) -- todo: better . handling
- return t .. "("
-end
-
-local lp_function = C(R("az","AZ","--","__")^1) * P("(") / function(t) -- todo: better . handling
- if expressions[t] then
- return "expressions." .. t .. "("
- else
- return "expressions.error("
- end
-end
-
-local lparent = lpeg.P("(")
-local rparent = lpeg.P(")")
-local noparent = 1 - (lparent+rparent)
-local nested = lpeg.P{lparent * (noparent + lpeg.V(1))^0 * rparent}
-local value = lpeg.P(lparent * lpeg.C((noparent + nested)^0) * rparent) -- lpeg.P{"("*C(((1-S("()"))+V(1))^0)*")"}
-
-local lp_child = Cc("expressions.child(r,k,'") * R("az","AZ","--","__")^1 * Cc("')")
-local lp_string = Cc("'") * R("az","AZ","--","__")^1 * Cc("'")
-local lp_content= Cc("tx==") * (P("'") * (1-P("'"))^0 * P("'") + P('"') * (1-P('"'))^0 * P('"'))
-
-
--- if we use a dedicated namespace then we don't need to pass rt and k
-
-local converter, cleaner
-
-local lp_special = (C(P("name")+P("text")+P("tag")+P("count")+P("child"))) * value / function(t,s)
- if expressions[t] then
- if s then
- return "expressions." .. t .. "(r,k," .. cleaner:match(s) ..")"
- else
- return "expressions." .. t .. "(r,k)"
- end
- else
- return "expressions.error(" .. t .. ")"
- end
-end
-
-local content =
- lp_position +
- lp_index +
- lp_text + lp_name + -- fast one
- lp_special +
- lp_noequal + lp_doequal +
- lp_attribute +
- lp_or + lp_and +
- lp_lua_function +
- lp_function +
- lp_reserved +
- lp_content +
- lp_child +
- lp_any
-
-converter = lpeg.Cs (
- (lpeg.P { lparent * (lpeg.V(1))^0 * rparent + content } )^0
-)
-
-cleaner = lpeg.Cs ( (
- lp_reserved +
- lp_string +
-1 )^1 )
-
--- expressions,root,rootdt,k,e,edt,ns,tg,idx,hsh[tg] or 1
-
-local template = [[
- -- todo: locals for xml.functions
- return function(expressions,r,d,k,e,dt,ns,tg,id,ps)
- local at, tx = e.at or { }, dt[1] or ""
- return %s
- end
-]]
-
-local function make_expression(str)
---~ print(">>>",str)
- str = converter:match(str)
---~ print("<<<",str)
- local s = loadstring(format(template,str))
- if s then
- return str, s()
- else
- return str, ""
- end
-end
-
-local space = S(' \r\n\t')
-local squote = S("'")
-local dquote = S('"')
-local lparent = P('(')
-local rparent = P(')')
-local atsign = P('@')
-local lbracket = P('[')
-local rbracket = P(']')
-local exclam = P('!')
-local period = P('.')
-local eq = P('==') + P('=')
-local ne = P('<>') + P('!=')
-local star = P('*')
-local slash = P('/')
-local colon = P(':')
-local bar = P('|')
-local hat = P('^')
-local valid = R('az', 'AZ', '09') + S('_-')
-local name_yes = C(valid^1 + star) * colon * C(valid^1 + star) -- permits ns:* *:tg *:*
-local name_nop = Cc("*") * C(valid^1)
-local name = name_yes + name_nop
-local number = C((S('+-')^0 * R('09')^1)) / tonumber
-local names = (bar^0 * name)^1
-local morenames = name * (bar^0 * name)^1
-local instructiontag = P('pi::')
-local spacing = C(space^0)
-local somespace = space^1
-local optionalspace = space^0
-local text = C(valid^0)
-local value = (squote * C((1 - squote)^0) * squote) + (dquote * C((1 - dquote)^0) * dquote)
-local empty = 1-slash
-local nobracket = 1-(lbracket+rbracket)
-
--- this has to become a proper grammar instead of a substitution (which we started
--- with when we moved to lpeg)
-
-local is_eq = lbracket * atsign * name * eq * value * rbracket * #(1-lbracket)
-local is_ne = lbracket * atsign * name * ne * value * rbracket * #(1-lbracket)
-local is_attribute = lbracket * atsign * name * rbracket * #(1-lbracket)
-local is_value = lbracket * value * rbracket * #(1-lbracket)
-local is_number = lbracket * number * rbracket * #(1-lbracket)
-local is_name = lbracket * name * rbracket * #(1-lbracket)
-
---~ local is_expression = lbracket * (C(nobracket^1))/make_expression * rbracket
---~ local is_expression = is_expression * (Cc(" and ") * is_expression)^0
-
---~ local is_expression = (lbracket/"(") * C(nobracket^1) * (rbracket/")")
---~ local is_expression = lpeg.Cs(is_expression * (Cc(" and ") * is_expression)^0) / make_expression
-
-local is_position = function(s) return " position()==" .. s .. " " end
-
-local is_expression = (is_number/is_position) + (lbracket/"(") * (nobracket^1) * (rbracket/")")
-local is_expression = lpeg.Cs(is_expression * (Cc(" and ") * is_expression)^0) / make_expression
-
-local is_one = name
-local is_none = exclam * name
-local is_one_of = ((lparent * names * rparent) + morenames)
-local is_none_of = exclam * ((lparent * names * rparent) + morenames)
-
---~ local stay_action = { 11 }, beware, sometimes we adapt !
-
-local stay = (period )
-local parent = (period * period ) / function( ) return { 11 } end
-local subtreeroot = (slash + hat ) / function( ) return { 12 } end
-local documentroot = (hat * hat ) / function( ) return { 13 } end
-local any = (star ) / function( ) return { 14 } end
-local many = (star * star ) / function( ) return { 15 } end
-local initial = (hat * hat * hat ) / function( ) return { 16 } end
-
-local match = (is_one ) / function(...) return { 20, true , ... } end
-local match_one_of = (is_one_of ) / function(...) return { 21, true , ... } end
-local dont_match = (is_none ) / function(...) return { 20, false, ... } end
-local dont_match_one_of = (is_none_of ) / function(...) return { 21, false, ... } end
-
-local match_and_eq = (is_one * is_eq ) / function(...) return { 22, true , ... } end
-local match_and_ne = (is_one * is_ne ) / function(...) return { 23, true , ... } end
-local dont_match_and_eq = (is_none * is_eq ) / function(...) return { 22, false, ... } end
-local dont_match_and_ne = (is_none * is_ne ) / function(...) return { 23, false, ... } end
-
-local match_one_of_and_eq = (is_one_of * is_eq ) / function(...) return { 24, true , ... } end
-local match_one_of_and_ne = (is_one_of * is_ne ) / function(...) return { 25, true , ... } end
-local dont_match_one_of_and_eq = (is_none_of * is_eq ) / function(...) return { 24, false, ... } end
-local dont_match_one_of_and_ne = (is_none_of * is_ne ) / function(...) return { 25, false, ... } end
-
-local has_name = (is_one * is_name) / function(...) return { 26, true , ... } end
-local dont_has_name = (is_none * is_name) / function(...) return { 26, false, ... } end
-local has_attribute = (is_one * is_attribute) / function(...) return { 27, true , ... } end
-local dont_has_attribute = (is_none * is_attribute) / function(...) return { 27, false, ... } end
-local has_value = (is_one * is_value ) / function(...) return { 28, true , ... } end
-local dont_has_value = (is_none * is_value ) / function(...) return { 28, false, ... } end
-local position = (is_one * is_number ) / function(...) return { 30, true, ... } end
-local dont_position = (is_none * is_number ) / function(...) return { 30, false, ... } end
-
-local expression = (is_one * is_expression)/ function(...) return { 31, true, ... } end
-local dont_expression = (is_none * is_expression)/ function(...) return { 31, false, ... } end
-
-local self_expression = ( is_expression) / function(...) return { 31, true, "*", "*", ... } end
-local dont_self_expression = (exclam * is_expression) / function(...) return { 31, false, "*", "*", ... } end
-
-local instruction = (instructiontag * text ) / function(...) return { 40, ... } end
-local nothing = (empty ) / function( ) return { 15 } end -- 15 ?
-local crap = (1-slash)^1
-
--- a few ugly goodies:
-
-local docroottag = P('^^') / function() return { 12 } end
-local subroottag = P('^') / function() return { 13 } end
-local roottag = P('root::') / function() return { 12 } end
-local parenttag = P('parent::') / function() return { 11 } end
-local childtag = P('child::')
-local selftag = P('self::')
-
--- there will be more and order will be optimized
-
-local selector = (
- instruction +
--- many + any + -- brrr, not here !
- parent + stay +
- dont_position + position + -- fast one
- dont_has_attribute + has_attribute + -- fast ones
- dont_has_name + has_name + -- fast ones
- dont_has_value + has_value + -- fast ones
- dont_match_one_of_and_eq + dont_match_one_of_and_ne +
- 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 +
- dont_self_expression + self_expression +
- dont_match_one_of + match_one_of +
- dont_match + match +
- many + any +
- crap + empty
-)
-
-local grammar = lpeg.Ct { "startup",
- startup = (initial + documentroot + subtreeroot + roottag + docroottag + subroottag)^0 * V("followup"),
- followup = ((slash + parenttag + childtag + selftag)^0 * selector)^1,
-}
-
-local function compose(str)
- if not str or str == "" then
- -- wildcard
- return true
- elseif str == '/' then
- -- root
- return false
- else
- local map = grammar:match(str)
- if #map == 0 then
- return true
- else
- if map[1][1] == 32 then
- -- lone expression
- insert(map, 1, { 11 })
- end
- local m = map[1][1]
- if #map == 1 then
- if m == 14 or m == 15 then
- -- wildcard
- return true
- elseif m == 12 then
- -- root
- return false
- end
- elseif #map == 2 and m == 12 and map[2][1] == 20 then
- 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
- insert(map, 1, { 16 })
- end
- return map
- end
- end
-end
-
-local cache = { }
-
-local function lpath(pattern,trace)
- lpathcalls = lpathcalls + 1
- if type(pattern) == "string" then
- local result = cache[pattern]
- if result == nil then -- can be false which is valid -)
- result = compose(pattern)
- cache[pattern] = result
- lpathcached = lpathcached + 1
- end
- if trace or trace_lpath then
- xml.lshow(result)
- end
- return result
- else
- return pattern
- end
-end
-
-xml.lpath = lpath
-
-function xml.cached_patterns()
- return cache
-end
-
--- we run out of locals (limited to 200)
---
--- local fallbackreport = (texio and texio.write) or io.write
-
-function xml.lshow(pattern,report)
--- report = report or fallbackreport
- report = report or (texio and texio.write) or io.write
- local lp = lpath(pattern)
- if lp == false then
- report(" -: root\n")
- elseif lp == true then
- report(" -: wildcard\n")
- else
- if type(pattern) == "string" then
- report(format("pattern: %s\n",pattern))
- end
- for k=1,#lp do
- local v = lp[k]
- if #v > 1 then
- local t = { }
- for i=2,#v do
- local vv = v[i]
- if type(vv) == "string" then
- t[#t+1] = (vv ~= "" and vv) or "#"
- elseif type(vv) == "boolean" then
- t[#t+1] = (vv and "==") or "<>"
- end
- end
- report(format("%2i: %s %s -> %s\n", k,v[1],actions[v[1]],concat(t," ")))
- else
- report(format("%2i: %s %s\n", k,v[1],actions[v[1]]))
- end
- end
- 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
- local report = (type(t[#t]) == "function" and t[#t]) or (texio and texio.write) or io.write
- if e == nil then
- report("<!-- no element -->\n")
- elseif type(e) ~= "table" then
- report(tostring(e))
- elseif e.tg then
- report(tostring(e) .. "\n")
- else
- for i=1,#e do
- report(tostring(e[i]) .. "\n")
- end
- end
-end
-
---[[ldx--
-<p>An <l n='lpath'/> is converted to a table with instructions for traversing the
-tree. Hoever, simple cases are signaled by booleans. Because we don't know in
-advance what we want to do with the found element the handle gets three arguments:</p>
-
-<lines>
-<t>r</t> : the root element of the data table
-<t>d</t> : the data table of the result
-<t>t</t> : the index in the data table of the result
-</lines>
-
-<p> Access to the root and data table makes it possible to construct insert and delete
-functions.</p>
---ldx]]--
-
-local functions = xml.functions
-local expressions = xml.expressions
-
-expressions.contains = string.find
-expressions.find = string.find
-expressions.upper = string.upper
-expressions.lower = string.lower
-expressions.number = tonumber
-expressions.boolean = toboolean
-
-expressions.oneof = function(s,...) -- slow
- local t = {...} for i=1,#t do if s == t[i] then return true end end return false
-end
-
-expressions.error = function(str)
- xml.error_handler("unknown function in lpath expression",str or "?")
- return false
-end
-
-functions.text = function(root,k,n) -- unchecked, maybe one deeper
---~ local t = type(t) -- ?
---~ if t == "string" then
---~ return t
---~ else -- todo n
- local rdt = root.dt
- return (rdt and rdt[k]) or root[k] or ""
---~ end
-end
-
-functions.name = function(d,k,n) -- ns + tg
- local found = false
- n = n or 0
- if not k then
- -- not found
- elseif n == 0 then
- local dk = d[k]
- found = dk and (type(dk) == "table") and dk
- elseif n < 0 then
- for i=k-1,1,-1 do
- local di = d[i]
- if type(di) == "table" then
- if n == -1 then
- found = di
- break
- else
- n = n + 1
- end
- end
- end
- else
- for i=k+1,#d,1 do
- local di = d[i]
- if type(di) == "table" then
- if n == 1 then
- found = di
- break
- else
- n = n - 1
- end
- end
- end
- end
- if found then
- local ns, tg = found.rn or found.ns or "", found.tg
- if ns ~= "" then
- return ns .. ":" .. tg
- else
- return tg
- end
- else
- return ""
- end
-end
-
-functions.tag = function(d,k,n) -- only tg
- local found = false
- n = n or 0
- if not k then
- -- not found
- elseif n == 0 then
- local dk = d[k]
- found = dk and (type(dk) == "table") and dk
- elseif n < 0 then
- for i=k-1,1,-1 do
- local di = d[i]
- if type(di) == "table" then
- if n == -1 then
- found = di
- break
- else
- n = n + 1
- end
- end
- end
- else
- for i=k+1,#d,1 do
- local di = d[i]
- if type(di) == "table" then
- if n == 1 then
- found = di
- break
- else
- n = n - 1
- end
- end
- end
- end
- return (found and found.tg) or ""
-end
-
-expressions.text = functions.text
-expressions.name = functions.name
-expressions.tag = functions.tag
-
-local function traverse(root,pattern,handle,reverse,index,parent,wildcard) -- multiple only for tags, not for namespaces
- if not root then -- error
- return false
- elseif pattern == false then -- root
- handle(root,root.dt,root.ri)
- return false
- elseif pattern == true then -- wildcard
- local rootdt = root.dt
- if rootdt then
- local start, stop, step = 1, #rootdt, 1
- if reverse then
- start, stop, step = stop, start, -1
- end
- for k=start,stop,step do
- if handle(root,rootdt,root.ri or k) then return false end
- if not traverse(rootdt[k],true,handle,reverse) then return false end
- end
- end
- return false
- elseif root.dt then
- index = index or 1
- local action = pattern[index]
- local command = action[1]
- if command == 29 then -- fast case /oeps
- local rootdt = root.dt
- for k=1,#rootdt do
- local e = rootdt[k]
- local tg = e.tg
- if e.tg then
- local ns = e.rn or e.ns
- local ns_a, tg_a = action[3], action[4]
- local matched = (ns_a == "*" or ns == ns_a) and (tg_a == "*" or tg == tg_a)
- if not action[2] then matched = not matched end
- if matched then
- if handle(root,rootdt,k) then return false end
- end
- end
- end
- elseif command == 11 then -- parent
- local ep = root.__p__ or parent
- if index < #pattern then
- if not traverse(ep,pattern,handle,reverse,index+1,root) then return false end
- elseif handle(ep) then -- wrong (others also)
- return false
- else
- -- ?
- end
- else
- if (command == 16 or command == 12) and index == 1 then -- initial
- -- wildcard = true
- wildcard = command == 16 -- ok?
- index = index + 1
- action = pattern[index]
- command = action and action[1] or 0 -- something is wrong
- end
- if command == 11 then -- parent
- local ep = root.__p__ or parent
- if index < #pattern then
- if not traverse(ep,pattern,handle,reverse,index+1,root) then return false end
- elseif handle(ep) then
- return false
- else
- -- ?
- end
- else
- local rootdt = root.dt
- local start, stop, step, n, dn = 1, #rootdt, 1, 0, 1
- if command == 30 then
- if action[5] < 0 then
- start, stop, step = stop, start, -1
- dn = -1
- end
- elseif reverse and index == #pattern then
- start, stop, step = stop, start, -1
- end
- local idx, hsh = 0, { } -- this hsh will slooow down the lot
- for k=start,stop,step do -- we used to have functions for all but a case is faster
- local e = rootdt[k]
- local ns, tg = e.rn or e.ns, e.tg
- if tg then
- -- we can optimize this for simple searches, but it probably does not pay off
- hsh[tg] = (hsh[tg] or 0) + 1
- idx = idx + 1
- if command == 30 then
- local ns_a, tg_a = action[3], action[4]
- if tg == tg_a then
- matched = ns_a == "*" or ns == ns_a
- elseif tg_a == '*' then
- matched, multiple = ns_a == "*" or ns == ns_a, 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
- if index == #pattern then
- if handle(root,rootdt,root.ri or k) then return false end
- else
- if not traverse(e,pattern,handle,reverse,index+1,root) then return false end
- end
- break
- end
- elseif wildcard then
- if not traverse(e,pattern,handle,reverse,index,root,true) then return false end
- end
- else
- local matched, multiple = false, false
- if command == 20 then -- match
- local ns_a, tg_a = action[3], action[4]
- if tg == tg_a then
- matched = ns_a == "*" or ns == ns_a
- elseif tg_a == '*' then
- matched, multiple = ns_a == "*" or ns == ns_a, 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=3,#action,2 do
- local ns_a, tg_a = action[i], action[i+1]
- if (ns_a == "*" or ns == ns_a) and (tg == "*" or tg == tg_a) then
- matched = true
- break
- end
- end
- if not action[2] then matched = not matched end
- elseif command == 22 then -- eq
- local ns_a, tg_a = action[3], action[4]
- if tg == tg_a then
- matched = ns_a == "*" or ns == ns_a
- elseif tg_a == '*' then
- matched, multiple = ns_a == "*" or ns == ns_a, true
- else
- matched = false
- end
- matched = matched and e.at[action[6]] == action[7]
- elseif command == 23 then -- ne
- local ns_a, tg_a = action[3], action[4]
- if tg == tg_a then
- matched = ns_a == "*" or ns == ns_a
- elseif tg_a == '*' then
- matched, multiple = ns_a == "*" or ns == ns_a, 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
- local ns_a, tg_a = action[i], action[i+1]
- if (ns_a == "*" or ns == ns_a) and (tg == "*" or tg == tg_a) then
- matched = true
- break
- end
- 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
- local ns_a, tg_a = action[i], action[i+1]
- if (ns_a == "*" or ns == ns_a) and (tg == "*" or tg == tg_a) then
- matched = true
- break
- end
- end
- if not action[2] then matched = not matched end
- matched = matched and e.at[action[#action-1]] ~= action[#action]
- elseif command == 26 then -- has child
- local ns_a, tg_a = action[3], action[4]
- if tg == tg_a then
- matched = ns_a == "*" or ns == ns_a
- elseif tg_a == '*' then
- matched, multiple = ns_a == "*" or ns == ns_a, true
- else
- matched = false
- end
- if not action[2] then matched = not matched end
- if matched then
- -- ok, we could have the whole sequence here ... but > 1 has become an expression
- local ns_a, tg_a, ok, edt = action[5], action[6], false, e.dt
- for k=1,#edt do
- local edk = edt[k]
- if type(edk) == "table" then
- if (ns_a == "*" or edk.ns == ns_a) and (edk.tg == tg_a) then
- ok = true
- break
- end
- end
- end
- matched = matched and ok
- end
- elseif command == 27 then -- has attribute
- local ns_a, tg_a = action[3], action[4]
- if tg == tg_a then
- matched = ns_a == "*" or ns == ns_a
- elseif tg_a == '*' then
- matched, multiple = ns_a == "*" or ns == ns_a, true
- else
- matched = false
- end
- if not action[2] then matched = not matched end
- matched = matched and e.at[action[6]]
- elseif command == 28 then -- has value (text match)
- local edt, ns_a, tg_a = e.dt, action[3], action[4]
- if tg == tg_a then
- matched = ns_a == "*" or ns == ns_a
- elseif tg_a == '*' then
- matched, multiple = ns_a == "*" or ns == ns_a, 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, ns_a, tg_a = e.dt, action[3], action[4]
- if tg == tg_a then
- matched = ns_a == "*" or ns == ns_a
- elseif tg_a == '*' then
- matched, multiple = ns_a == "*" or ns == ns_a, true
- else
- matched = false
- end
- if not action[2] then matched = not matched end
- if matched then
- matched = action[6](expressions,root,rootdt,k,e,edt,ns,tg,idx,hsh[tg] or 1)
- end
- end
- if matched then -- combine tg test and at test
- if index == #pattern then
- if handle(root,rootdt,root.ri or k) then return false end
- if wildcard then
- if multiple then
- if not traverse(e,pattern,handle,reverse,index,root,true) then return false end
- else
- -- maybe or multiple; anyhow, check on (section|title) vs just section and title in example in lxml
- if not traverse(e,pattern,handle,reverse,index,root) then return false end
- end
- end
- else
- -- todo: [expr][expr]
- if not traverse(e,pattern,handle,reverse,index+1,root) then return false end
- end
- elseif command == 14 then -- any
- if index == #pattern then
- if handle(root,rootdt,root.ri or k) then return false end
- else
- if not traverse(e,pattern,handle,reverse,index+1,root) then return false end
- end
- elseif command == 15 then -- many
- if index == #pattern then
- if handle(root,rootdt,root.ri or k) then return false end
- else
- if not traverse(e,pattern,handle,reverse,index+1,root,true) then return false end
- end
- -- not here : 11
- elseif command == 11 then -- parent
- local ep = e.__p__ or parent
- if index < #pattern then
- if not traverse(ep,pattern,handle,reverse,root,index+1) then return false end
- elseif handle(root,rootdt,k) then
- return false
- end
- elseif command == 40 and e.special and tg == "@pi@" then -- pi
- local pi = action[2]
- if pi ~= "" then
- local pt = e.dt[1]
- if pt and pt:find(pi) then
- if handle(root,rootdt,k) then
- return false
- end
- end
- elseif handle(root,rootdt,k) then
- return false
- end
- elseif wildcard then
- if not traverse(e,pattern,handle,reverse,index,root,true) then return false end
- end
- end
- else
- -- not here : 11
- if command == 11 then -- parent
- local ep = e.__p__ or parent
- if index < #pattern then
- if not traverse(ep,pattern,handle,reverse,index+1,root) then return false end
- elseif handle(ep) then
- return false
- else
- --
- end
- break -- else loop
- end
- end
- end
- end
- end
- end
- return true
-end
-
-xml.traverse = traverse
-
-expressions.child = function(root,k,what) -- we could move the lpath converter to the scanner
- local ok = false
- traverse(root.dt[k],lpath(what),function(r,d,t) ok = true return true end)
- return ok
-end
-
-expressions.count = function(root,k,what) -- we could move the lpath converter to the scanner
- local n = 0
- traverse(root.dt[k],lpath(what),function(r,d,t) n = n + 1 return false end)
- return n
-end
-
---[[ldx--
-<p>Next come all kind of locators and manipulators. The most generic function here
-is <t>xml.filter(root,pattern)</t>. All registers functions in the filters namespace
-can be path of a search path, as in:</p>
-
-<typing>
-local r, d, k = xml.filter(root,"/a/b/c/position(4)"
-</typing>
---ldx]]--
-
-xml.filters = { }
-
-local traverse, lpath, convert = xml.traverse, xml.lpath, xml.convert
-
-local filters = xml.filters
-
-function filters.default(root,pattern)
- local rt, dt, dk
- traverse(root, lpath(pattern), function(r,d,k) rt,dt,dk = r,d,k return true end)
- return dt and dt[dk], rt, dt, dk
-end
-
-function filters.attributes(root,pattern,arguments)
- local rt, dt, dk
- traverse(root, lpath(pattern), function(r,d,k) rt, dt, dk = r, d, k return true end)
- local ekat = (dt and dt[dk] and dt[dk].at) or (rt and rt.at)
- if ekat then
- if arguments then
- return ekat[arguments] or "", rt, dt, dk
- else
- return ekat, rt, dt, dk
- end
- else
- return { }, rt, dt, dk
- end
-end
-
--- new
-
-local rt, dt, dk
-
-local function action(r,d,k) rt, dt, dk = r, d, k return true end
-
-function filters.chainattribute(root,pattern,arguments) -- todo: optional levels
- rt, dt, dk = nil, nil, nil
- traverse(root, lpath(pattern), action)
- local dtk = dt and dt[dk]
- local ekat = (dtk and dtk.at) or (rt and rt.at)
- local rp = rt
- while true do
- if ekat then
- local a = ekat[arguments]
- if a then
- return a, rt, dt, dk
- end
- end
- rp = rp.__p__
- if rp then
- ekat = rp.at
- else
- return "", rt, dt, dk
- end
- end
-end
-
---
-
-function filters.reverse(root,pattern)
- local rt, dt, dk
- traverse(root, lpath(pattern), function(r,d,k) rt,dt,dk = r,d,k return true end, 'reverse')
- return dt and dt[dk], rt, dt, dk
-end
-
-function filters.count(root,pattern,everything)
- local n = 0
- traverse(root, lpath(pattern), function(r,d,t)
- if everything or type(d[t]) == "table" then
- n = n + 1
- end
- end)
- return n
-end
-
---~ local n = 0
---~ local function doit(r,d,t)
---~ if everything or type(d[t]) == "table" then
---~ n = n + 1
---~ end
---~ end
---~ function filters.count(root,pattern,everything)
---~ n = 0
---~ traverse(root, lpath(pattern), doit)
---~ return n
---~ end
-
-function filters.elements(root, pattern) -- == all
- local t = { }
- traverse(root, lpath(pattern), function(r,d,k)
- local e = d[k]
- if e then
- t[#t+1] = e
- end
- end)
- return t
-end
-
-function filters.texts(root, pattern)
- local t = { }
- traverse(root, lpath(pattern), function(r,d,k)
- local e = d[k]
- if e and e.dt then
- t[#t+1] = e.dt
- end
- end)
- return t
-end
-
-function filters.first(root,pattern)
- local rt, dt, dk
- traverse(root, lpath(pattern), function(r,d,k) rt,dt,dk = r,d,k return true end)
- return dt and dt[dk], rt, dt, dk
-end
-
-function filters.last(root,pattern)
- local rt, dt, dk
- traverse(root, lpath(pattern), function(r,d,k) rt,dt,dk = r,d,k return true end, 'reverse')
- return dt and dt[dk], rt, dt, dk
-end
-
-function filters.index(root,pattern,arguments)
- local rt, dt, dk, reverse, i = nil, nil, nil, false, tonumber(arguments or '1') or 1
- if i and i ~= 0 then
- if i < 0 then
- reverse, i = true, -i
- end
- traverse(root, lpath(pattern), function(r,d,k) rt, dt, dk, i = r, d, k, i-1 return i == 0 end, reverse)
- if i == 0 then
- return dt and dt[dk], rt, dt, dk
- end
- end
- return nil, nil, nil, nil
-end
-
---~ function filters.attribute(root,pattern,arguments)
---~ local rt, dt, dk
---~ traverse(root, lpath(pattern), function(r,d,k) rt, dt, dk = r, d, k return true end)
---~ local ekat = (dt and dt[dk] and dt[dk].at) or (rt and rt.at)
---~ return (ekat and (ekat[arguments] or (find(arguments,"^[\'\"]") and ekat[sub(arguments,2,-2)]))) or ""
---~ end
-
-local rt, dt, dk
-local function doit(r,d,k) rt, dt, dk = r, d, k return true end
-function filters.attribute(root,pattern,arguments)
- rt, dt, dk = nil, nil, nil
- traverse(root, lpath(pattern), doit)
- local dtk = dt and dt[k]
- local ekat = (dtk and dtk.at) or (rt and rt.at)
- return (ekat and (ekat[arguments] or (find(arguments,"^[\'\"]") and ekat[sub(arguments,2,-2)]))) or ""
-end
-
-function filters.text(root,pattern,arguments) -- ?? why index, tostring slow
- local dtk, rt, dt, dk = filters.index(root,pattern,arguments)
- if dtk then -- n
- local dtkdt = dtk.dt
- if not dtkdt then
- return "", rt, dt, dk
- elseif #dtkdt == 1 and type(dtkdt[1]) == "string" then
- return dtkdt[1], rt, dt, dk
- else
- return xml.tostring(dtkdt), rt, dt, dk
- end
- else
- return "", rt, dt, dk
- end
-end
-
-function filters.tag(root,pattern,n)
- local tag = ""
- traverse(root, lpath(pattern), function(r,d,k)
- tag = xml.functions.tag(d,k,n and tonumber(n))
- return true
- end)
- return tag
-end
-
-function filters.name(root,pattern,n)
- local tag = ""
- traverse(root, lpath(pattern), function(r,d,k)
- tag = xml.functions.name(d,k,n and tonumber(n))
- return true
- end)
- return tag
-end
-
---[[ldx--
-<p>For splitting the filter function from the path specification, we can
-use string matching or lpeg matching. Here the difference in speed is
-neglectable but the lpeg variant is more robust.</p>
---ldx]]--
-
--- not faster but hipper ... although ... i can't get rid of the trailing / in the path
-
-local P, S, R, C, V, Cc = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc
-
-local slash = P('/')
-local name = (R("az","AZ","--","__"))^1
-local path = C(((1-slash)^0 * slash)^1)
-local argument = P { "(" * C(((1 - S("()")) + V(1))^0) * ")" }
-local action = Cc(1) * path * C(name) * argument
-local attribute = Cc(2) * path * P('@') * C(name)
-local direct = Cc(3) * Cc("../*") * slash^0 * C(name) * argument
-
-local parser = direct + action + attribute
-
-local filters = xml.filters
-local attribute_filter = xml.filters.attributes
-local default_filter = xml.filters.default
-
--- todo: also hash, could be gc'd
-
-function xml.filter(root,pattern)
- local kind, a, b, c = parser:match(pattern)
- if kind == 1 or kind == 3 then
- return (filters[b] or default_filter)(root,a,c)
- elseif kind == 2 then
- return attribute_filter(root,a,b)
- else
- return default_filter(root,pattern)
- end
-end
-
---~ slightly faster, but first we need a proper test file
---~
---~ local hash = { }
---~
---~ function xml.filter(root,pattern)
---~ local h = hash[pattern]
---~ if not h then
---~ local kind, a, b, c = parser:match(pattern)
---~ if kind == 1 then
---~ h = { kind, filters[b] or default_filter, a, b, c }
---~ elseif kind == 2 then
---~ h = { kind, attribute_filter, a, b, c }
---~ else
---~ h = { kind, default_filter, a, b, c }
---~ end
---~ hash[pattern] = h
---~ end
---~ local kind = h[1]
---~ if kind == 1 then
---~ return h[2](root,h[2],h[4])
---~ elseif kind == 2 then
---~ return h[2](root,h[2],h[3])
---~ else
---~ return h[2](root,pattern)
---~ end
---~ end
-
---[[ldx--
-<p>The following functions collect elements and texts.</p>
---ldx]]--
-
--- still somewhat bugged
-
-function xml.collect_elements(root, pattern, ignorespaces)
- local rr, dd = { }, { }
- traverse(root, lpath(pattern), function(r,d,k)
- local dk = d and d[k]
- if dk then
- if ignorespaces and type(dk) == "string" and dk:find("[^%S]") then
- -- ignore
- else
- local n = #rr+1
- rr[n], dd[n] = r, dk
- end
- end
- end)
- return dd, rr
-end
-
-function xml.collect_texts(root, pattern, flatten)
- local t = { } -- no r collector
- traverse(root, lpath(pattern), function(r,d,k)
- if d then
- local ek = d[k]
- local tx = ek and ek.dt
- if flatten then
- if tx then
- t[#t+1] = xml.tostring(tx) or ""
- else
- t[#t+1] = "" -- hm
- end
- else
- t[#t+1] = tx or ""
- end
- else
- t[#t+1] = "" -- hm
- end
- end)
- return t
-end
-
-function xml.collect_tags(root, pattern, nonamespace)
- local t = { }
- xml.traverse(root, lpath(pattern), function(r,d,k)
- local dk = d and d[k]
- if dk and type(dk) == "table" then
- local ns, tg = e.ns, e.tg
- if nonamespace then
- t[#t+1] = tg -- if needed we can return an extra table
- elseif ns == "" then
- t[#t+1] = tg
- else
- t[#t+1] = ns .. ":" .. tg
- end
- end
- end)
- return #t > 0 and {}
-end
-
---[[ldx--
-<p>Often using an iterators looks nicer in the code than passing handler
-functions. The <l n='lua'/> book describes how to use coroutines for that
-purpose (<url href='http://www.lua.org/pil/9.3.html'/>). This permits
-code like:</p>
-
-<typing>
-for r, d, k in xml.elements(xml.load('text.xml'),"title") do
- print(d[k])
-end
-</typing>
-
-<p>Which will print all the titles in the document. The iterator variant takes
-1.5 times the runtime of the function variant which is due to the overhead in
-creating the wrapper. So, instead of:</p>
-
-<typing>
-function xml.filters.first(root,pattern)
- for rt,dt,dk in xml.elements(root,pattern)
- return dt and dt[dk], rt, dt, dk
- end
- return nil, nil, nil, nil
-end
-</typing>
-
-<p>We use the function variants in the filters.</p>
---ldx]]--
-
-local wrap, yield = coroutine.wrap, coroutine.yield
-
-function xml.elements(root,pattern,reverse)
- return wrap(function() traverse(root, lpath(pattern), yield, reverse) end)
-end
-
-function xml.elements_only(root,pattern,reverse)
- return wrap(function() traverse(root, lpath(pattern), function(r,d,k) yield(d[k]) end, reverse) end)
-end
-
-function xml.each_element(root, pattern, handle, reverse)
- local ok
- traverse(root, lpath(pattern), function(r,d,k) ok = true handle(r,d,k) end, reverse)
- return ok
-end
-
---~ todo:
---~
---~ function xml.process_elements(root, pattern, handle)
---~ traverse(root, lpath(pattern), fnc, nil, nil, nil, handle) -> fnc gets r, d, k and handle (...) passed
-
-function xml.process_elements(root, pattern, handle)
- traverse(root, lpath(pattern), function(r,d,k)
- local dkdt = d[k].dt
- if dkdt then
- for i=1,#dkdt do
- local v = dkdt[i]
- if v.tg then handle(v) end
- end
- end
- end)
-end
-
-function xml.process_attributes(root, pattern, handle)
- traverse(root, lpath(pattern), function(r,d,k)
- local ek = d[k]
- local a = ek.at or { }
- handle(a)
- if next(a) then -- next is faster than type (and >0 test)
- ek.at = a
- else
- ek.at = nil
- end
- end)
-end
-
---[[ldx--
-<p>We've now arrives at the functions that manipulate the tree.</p>
---ldx]]--
-
-function xml.inject_element(root, pattern, element, prepend)
- if root and element then
- local matches, collect = { }, nil
- if type(element) == "string" then
- element = convert(element,true)
- end
- if element then
- collect = function(r,d,k) matches[#matches+1] = { r, d, k, element } end
- traverse(root, lpath(pattern), collect)
- for i=1,#matches do
- local m = matches[i]
- local r, d, k, element, edt = m[1], m[2], m[3], m[4], nil
- if element.ri then
- element = element.dt[element.ri].dt
- else
- element = element.dt
- end
- if r.ri then
- edt = r.dt[r.ri].dt
- else
- edt = d and d[k] and d[k].dt
- end
- if edt then
- local be, af
- if prepend then
- be, af = xml.copy(element), edt
- else
- be, af = edt, xml.copy(element)
- end
- for i=1,#af do
- be[#be+1] = af[i]
- end
- if r.ri then
- r.dt[r.ri].dt = be
- else
- d[k].dt = be
- end
- else
- -- r.dt = element.dt -- todo
- end
- end
- end
- end
-end
-
--- todo: copy !
-
-function xml.insert_element(root, pattern, element, before) -- todo: element als functie
- if root and element then
- if pattern == "/" then
- xml.inject_element(root, pattern, element, before)
- else
- local matches, collect = { }, nil
- if type(element) == "string" then
- element = convert(element,true)
- end
- if element and element.ri then
- element = element.dt[element.ri]
- end
- if element then
- collect = function(r,d,k) matches[#matches+1] = { r, d, k, element } end
- traverse(root, lpath(pattern), collect)
- for i=#matches,1,-1 do
- local m = matches[i]
- local r, d, k, element = m[1], m[2], m[3], m[4]
- if not before then k = k + 1 end
- if element.tg then
- insert(d,k,element) -- untested
---~ elseif element.dt then
---~ for _,v in ipairs(element.dt) do -- i added
---~ insert(d,k,v)
---~ k = k + 1
---~ end
---~ end
- else
- local edt = element.dt
- if edt then
- for i=1,#edt do
- insert(d,k,edt[i])
- k = k + 1
- end
- end
- end
- end
- end
- end
- end
-end
-
-xml.insert_element_after = xml.insert_element
-xml.insert_element_before = function(r,p,e) xml.insert_element(r,p,e,true) end
-xml.inject_element_after = xml.inject_element
-xml.inject_element_before = function(r,p,e) xml.inject_element(r,p,e,true) end
-
-function xml.delete_element(root, pattern)
- local matches, deleted = { }, { }
- local collect = function(r,d,k) matches[#matches+1] = { r, d, k } end
- traverse(root, lpath(pattern), collect)
- for i=#matches,1,-1 do
- local m = matches[i]
- deleted[#deleted+1] = remove(m[2],m[3])
- end
- return deleted
-end
-
-function xml.replace_element(root, pattern, element)
- if type(element) == "string" then
- element = convert(element,true)
- end
- if element and element.ri then
- element = element.dt[element.ri]
- end
- if element then
- traverse(root, lpath(pattern), function(rm, d, k)
- d[k] = element.dt -- maybe not clever enough
- end)
- end
-end
-
-local function load_data(name) -- == io.loaddata
- local f, data = io.open(name), ""
- if f then
- data = f:read("*all",'b') -- 'b' ?
- f:close()
- end
- return data
-end
-
-function xml.include(xmldata,pattern,attribute,recursive,loaddata)
- -- parse="text" (default: xml), encoding="" (todo)
- -- attribute = attribute or 'href'
- pattern = pattern or 'include'
- loaddata = loaddata or load_data
- local function include(r,d,k)
- local ek, name = d[k], nil
- if not attribute or attribute == "" then
- local ekdt = ek.dt
- name = (type(ekdt) == "table" and ekdt[1]) or ekdt
- end
- if not name then
- if ek.at then
- for a in gmatch(attribute or "href","([^|]+)") do
- name = ek.at[a]
- if name then break end
- end
- end
- end
- local data = (name and name ~= "" and loaddata(name)) or ""
- if data == "" then
- xml.empty(d,k)
- elseif ek.at["parse"] == "text" then -- for the moment hard coded
- d[k] = xml.escaped(data)
- else
- -- data, no_root, strip_cm_and_dt, given_entities, parent_root (todo: entities)
- local xi = xml.convert(data,nil,nil,xmldata.entities,xmldata)
- if not xi then
- xml.empty(d,k)
- else
- if recursive then
- xml.include(xi,pattern,attribute,recursive,loaddata)
- end
- xml.assign(d,k,xi)
- end
- end
- end
- xml.each_element(xmldata, pattern, include)
-end
-
-function xml.strip_whitespace(root, pattern, nolines) -- strips all leading and trailing space !
- traverse(root, lpath(pattern), function(r,d,k)
- local dkdt = d[k].dt
- if dkdt then -- can be optimized
- local t = { }
- for i=1,#dkdt do
- local str = dkdt[i]
- if type(str) == "string" then
- if str == "" then
- -- stripped
- else
- if nolines then
- str = gsub(str,"[ \n\r\t]+"," ")
- end
- if str == "" then
- -- stripped
- else
- t[#t+1] = str
- end
- end
- else
- t[#t+1] = str
- end
- end
- d[k].dt = t
- end
- end)
-end
-
-local function rename_space(root, oldspace, newspace) -- fast variant
- local ndt = #root.dt
- for i=1,ndt or 0 do
- local e = root[i]
- if type(e) == "table" then
- if e.ns == oldspace then
- e.ns = newspace
- if e.rn then
- e.rn = newspace
- end
- end
- local edt = e.dt
- if edt then
- rename_space(edt, oldspace, newspace)
- end
- end
- end
-end
-
-xml.rename_space = rename_space
-
-function xml.remap_tag(root, pattern, newtg)
- traverse(root, lpath(pattern), function(r,d,k)
- d[k].tg = newtg
- end)
-end
-function xml.remap_namespace(root, pattern, newns)
- traverse(root, lpath(pattern), function(r,d,k)
- d[k].ns = newns
- end)
-end
-function xml.check_namespace(root, pattern, newns)
- traverse(root, lpath(pattern), function(r,d,k)
- local dk = d[k]
- if (not dk.rn or dk.rn == "") and dk.ns == "" then
- dk.rn = newns
- end
- end)
-end
-function xml.remap_name(root, pattern, newtg, newns, newrn)
- traverse(root, lpath(pattern), function(r,d,k)
- local dk = d[k]
- dk.tg = newtg
- dk.ns = newns
- dk.rn = newrn
- 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
-
---[[ldx--
-<p>Here are a few synonyms.</p>
---ldx]]--
-
-xml.filters.position = xml.filters.index
-
-xml.count = xml.filters.count
-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
-xml.strip = xml.strip_whitespace
-xml.collect = xml.collect_elements
-xml.all = xml.collect_elements
-
-xml.insert = xml.insert_element_after
-xml.inject = xml.inject_element_after
-xml.after = xml.insert_element_after
-xml.before = xml.insert_element_before
-xml.delete = xml.delete_element
-xml.replace = xml.replace_element
-
---[[ldx--
-<p>The following helper functions best belong to the <t>lmxl-ini</t>
-module. Some are here because we need then in the <t>mk</t>
-document and other manuals, others came up when playing with
-this module. Since this module is also used in <l n='mtxrun'/> we've
-put them here instead of loading mode modules there then needed.</p>
---ldx]]--
-
-function xml.gsub(t,old,new)
- local dt = t.dt
- if dt then
- for k=1,#dt do
- local v = dt[k]
- if type(v) == "string" then
- dt[k] = gsub(v,old,new)
- else
- xml.gsub(v,old,new)
- end
- end
- end
-end
-
-function xml.strip_leading_spaces(dk,d,k) -- cosmetic, for manual
- if d and k and d[k-1] and type(d[k-1]) == "string" then
- local s = d[k-1]:match("\n(%s+)")
- xml.gsub(dk,"\n"..rep(" ",#s),"\n")
- end
-end
-
-function xml.serialize_path(root,lpath,handle)
- local dk, r, d, k = xml.first(root,lpath)
- dk = xml.copy(dk)
- xml.strip_leading_spaces(dk,d,k)
- 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
-
---~ function xml.escaped (str) return (gsub(str,"(.)" , xml.escapes )) end
---~ function xml.unescaped(str) return (gsub(str,"(&.-;)", xml.unescapes)) end
---~ function xml.cleansed (str) return (gsub(str,"<.->" , '' )) end -- "%b<>"
-
-local P, S, R, C, V, Cc, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc, lpeg.Cs
-
--- 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 = Cs((S("<&>") / xml.escapes + 1)^0)
--- escaped = Cs((S("<")/"&lt;" + S(">")/"&gt;" + S("&")/"&amp;" + 1)^0)
-local normal = (1 - S("<&>"))^0
-local special = P("<")/"&lt;" + P(">")/"&gt;" + P("&")/"&amp;"
-local escaped = Cs(normal * (special * normal)^0)
-
--- 100 * 1000 * "oeps&lt; oeps&gt; oeps&amp;" : gsub:lpeg == 0153:0280:0151:0080 (last one by roberto)
-
--- unescaped = Cs((S("&lt;")/"<" + S("&gt;")/">" + S("&amp;")/"&" + 1)^0)
--- unescaped = Cs((((P("&")/"") * (P("lt")/"<" + P("gt")/">" + P("amp")/"&") * (P(";")/"")) + 1)^0)
-local normal = (1 - S"&")^0
-local special = P("&lt;")/"<" + P("&gt;")/">" + P("&amp;")/"&"
-local unescaped = 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 = Cs(((P("<") * (1-P(">"))^0 * 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
-
-function xml.join(t,separator,lastseparator)
- if #t > 0 then
- local result = { }
- for k,v in pairs(t) do
- result[k] = xml.tostring(v)
- end
- if lastseparator then
- return concat(result,separator or "",1,#result-1) .. (lastseparator or "") .. result[#result]
- else
- return concat(result,separator)
- end
- else
- return ""
- end
-end
-
-function xml.statistics()
- return {
- lpathcalls = lpathcalls,
- lpathcached = lpathcached,
- }
-end
-
--- xml.set_text_cleanup(xml.show_text_entities)
--- xml.set_text_cleanup(xml.resolve_text_entities)
-
---~ xml.lshow("/../../../a/(b|c)[@d='e']/f")
---~ xml.lshow("/../../../a/!(b|c)[@d='e']/f")
---~ xml.lshow("/../../../a/!b[@d!='e']/f")
---~ xml.lshow("a[text()=='b']")
---~ xml.lshow("a['b']")
---~ xml.lshow("(x|y)[b]")
---~ xml.lshow("/aaa[bbb]")
---~ xml.lshow("aaa[bbb][ccc][ddd]")
---~ xml.lshow("aaa['xxx']")
---~ xml.lshow("a[b|c]")
---~ xml.lshow("whatever['crap']")
---~ xml.lshow("whatever[count(whocares) > 1 and oeps and 'oeps']")
---~ xml.lshow("whatever[whocares]")
---~ xml.lshow("whatever[@whocares]")
---~ xml.lshow("whatever[count(whocares) > 1]")
---~ xml.lshow("a(@b)")
---~ xml.lshow("a[b|c|d]")
---~ xml.lshow("a[b and @b]")
---~ xml.lshow("a[b]")
---~ xml.lshow("a[b and b]")
---~ xml.lshow("a[b][c]")
---~ xml.lshow("a[b][1]")
---~ xml.lshow("a[1]")
---~ xml.lshow("a[count(b)!=0][count(b)!=0]")
---~ xml.lshow("a[not(count(b))][not(count(b))]")
---~ xml.lshow("a[count(b)!=0][count(b)!=0]")
-
---~ 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.settrace("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>
---~ ]]
-
---~ x = xml.convert([[
---~ <a><b n='01'>01</b><b n='02'>02</b><x>xx</x><b n='03'>03</b><b n='04'>OK</b></a>
---~ ]])
---~ xml.xshow(xml.first(x,"b[tag(2) == 'x']"))
---~ xml.xshow(xml.first(x,"b[tag(1) == 'x']"))
---~ xml.xshow(xml.first(x,"b[tag(-1) == 'x']"))
---~ xml.xshow(xml.first(x,"b[tag(-2) == 'x']"))
-
---~ print(xml.filter(x,"b/tag(2)"))
---~ print(xml.filter(x,"b/tag(1)"))
diff --git a/tex/context/base/lxml-sor.lua b/tex/context/base/lxml-sor.lua
index 5ef94cbf2..f2bb756f2 100644
--- a/tex/context/base/lxml-sor.lua
+++ b/tex/context/base/lxml-sor.lua
@@ -122,18 +122,16 @@ function lxml.sorters.flush(name,setup)
if results and next(results) then
for key, result in next, results do
local tag, data = result.tag, result.data
---~ tex.sprint(ctxcatcodes,format("key=%s\\quad tag=%s\\blank",key,tag))
for d=1,#data do
local dr = data[d]
- texsprint(ctxcatcodes,format("\\xmls{%s}{%s}",dr.entry,setup))
+ texsprint(ctxcatcodes,"\\xmlw{",setup,"}{",dr.entry,"}")
end
---~ tex.sprint(ctxcatcodes,format("\\blank"))
end
else
local entries = list and list.entries
if entries then
for i=1,#entries do
- texsprint(ctxcatcodes,format("\\xmls{%s}{%s}",entries[i][1],setup))
+ texsprint(ctxcatcodes,"\\xmlw{",setup,"}{",entries[i][1],"}")
end
end
end
diff --git a/tex/context/base/lxml-tab.lua b/tex/context/base/lxml-tab.lua
index b49bf0ecb..faafa4462 100644
--- a/tex/context/base/lxml-tab.lua
+++ b/tex/context/base/lxml-tab.lua
@@ -10,6 +10,8 @@ if not modules then modules = { } end modules ['lxml-tab'] = {
-- stripping spaces from e.g. cont-en.xml saves .2 sec runtime so it's not worth the
-- trouble
+local trace_entities = false trackers.register("xml.entities", function(v) trace_entities = v end)
+
--[[ldx--
<p>The parser used here is inspired by the variant discussed in the lua book, but
handles comment and processing instructions, has a different structure, provides
@@ -17,18 +19,6 @@ parent access; a first version used different trickery but was less optimized to
went this route. First we had a find based parser, now we have an <l n='lpeg'/> based one.
The find based parser can be found in l-xml-edu.lua along with other older code.</p>
-<p>Expecially the lpath code is experimental, we will support some of xpath, but
-only things that make sense for us; as compensation it is possible to hook in your
-own functions. Apart from preprocessing content for <l n='context'/> we also need
-this module for process management, like handling <l n='ctx'/> and <l n='rlx'/>
-files.</p>
-
-<typing>
-a/b/c /*/c
-a/b/c/first() a/b/c/last() a/b/c/index(n) a/b/c/index(-n)
-a/b/c/text() a/b/c/text(1) a/b/c/text(-1) a/b/c/text(n)
-</typing>
-
<p>Beware, the interface may change. For instance at, ns, tg, dt may get more
verbose names. Once the code is stable we will also remove some tracing and
optimize the code.</p>
@@ -39,26 +29,9 @@ xml = xml or { }
--~ local xml = xml
local concat, remove, insert = table.concat, table.remove, table.insert
-local type, next, setmetatable, getmetatable = type, next, setmetatable, getmetatable
+local type, next, setmetatable, getmetatable, tonumber = type, next, setmetatable, getmetatable, tonumber
local format, lower, find = string.format, string.lower, string.find
-
---[[ldx--
-<p>This module can be used stand alone but also inside <l n='mkiv'/> in
-which case it hooks into the tracker code. Therefore we provide a few
-functions that set the tracers.</p>
---ldx]]--
-
-local trace_remap = false
-
-if trackers then
- trackers.register("xml.remap", function(v) trace_remap = v end)
-end
-
-function xml.settrace(str,value)
- if str == "remap" then
- trace_remap = value or false
- end
-end
+local utfchar = unicode.utf8.char
--[[ldx--
<p>First a hack to enable namespace resolving. A namespace is characterized by
@@ -165,17 +138,16 @@ element.</p>
</typing>
--ldx]]--
-xml.strip_cm_and_dt = false -- an extra global flag, in case we have many includes
-
-- not just one big nested table capture (lpeg overflow)
local nsremap, resolvens = xml.xmlns, xml.resolvens
local stack, top, dt, at, xmlns, errorstr, entities = {}, {}, {}, {}, {}, nil, {}
+local strip, cleanup, utfize, resolve = false, false, false, false
-local mt = { __tostring = xml.text }
+local mt = { }
-function initialize_mt(root)
+function initialize_mt(root) -- we will make a xml.new that then sets the mt as field
mt = { __tostring = xml.text, __index = root }
end
@@ -187,13 +159,6 @@ function xml.check_error(top,toclose)
return ""
end
-local strip = false
-local cleanup = false
-
-function xml.set_text_cleanup(fnc)
- cleanup = fnc
-end
-
local function add_attribute(namespace,tag,value)
if cleanup and #value > 0 then
value = cleanup(value) -- new
@@ -209,6 +174,22 @@ local function add_attribute(namespace,tag,value)
end
end
+local function add_empty(spacing, namespace, tag)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ local resolved = (namespace == "" and xmlns[#xmlns]) or nsremap[namespace] or namespace
+ top = stack[#stack]
+ dt = top.dt
+ local t = { ns=namespace or "", rn=resolved, tg=tag, at=at, dt={}, __p__ = top }
+ dt[#dt+1] = t
+ setmetatable(t, mt)
+ if at.xmlns then
+ remove(xmlns)
+ end
+ at = { }
+end
+
local function add_begin(spacing, namespace, tag)
if #spacing > 0 then
dt[#dt+1] = spacing
@@ -234,28 +215,12 @@ local function add_end(spacing, namespace, tag)
end
dt = top.dt
dt[#dt+1] = toclose
- dt[0] = top
+ -- dt[0] = top -- nasty circular reference when serializing table
if toclose.at.xmlns then
remove(xmlns)
end
end
-local function add_empty(spacing, namespace, tag)
- if #spacing > 0 then
- dt[#dt+1] = spacing
- end
- local resolved = (namespace == "" and xmlns[#xmlns]) or nsremap[namespace] or namespace
- top = stack[#stack]
- dt = top.dt
- local t = { ns=namespace or "", rn=resolved, tg=tag, at=at, dt={}, __p__ = top }
- dt[#dt+1] = t
- setmetatable(t, mt)
- if at.xmlns then
- remove(xmlns)
- end
- at = { }
-end
-
local function add_text(text)
if cleanup and #text > 0 then
dt[#dt+1] = cleanup(text)
@@ -279,7 +244,109 @@ local function set_message(txt)
errorstr = "garbage at the end of the file: " .. gsub(txt,"([ \n\r\t]*)","")
end
-local P, S, R, C, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V
+local reported_attribute_errors = { }
+
+local function attribute_value_error(str)
+ if not reported_attribute_errors[str] then
+ logs.report("xml","invalid attribute value: %q",str)
+ reported_attribute_errors[str] = true
+ at._error_ = str
+ end
+ return str
+end
+local function attribute_specification_error(str)
+ if not reported_attribute_errors[str] then
+ logs.report("xml","invalid attribute specification: %q",str)
+ reported_attribute_errors[str] = true
+ at._error_ = str
+ end
+ return str
+end
+
+local dcache, hcache, acache = { }, { }, { }
+
+function xml.unknown_dec_entity_format(str) return format("&%s;", str) end
+function xml.unknown_hex_entity_format(str) return format("&#x%s;",str) end
+function xml.unknown_any_entity_format(str) return format("&%s;", str) end
+
+local function handle_hex_entity(str)
+ local h = hcache[str]
+ if not h then
+ if utfize then
+ local n = tonumber(str,16)
+ h = (n and utfchar(n)) or xml.unknown_hex_entity_format(str) or ""
+ if not n then
+ logs.report("xml","utfize, ignoring hex entity &#x%s;",str)
+ elseif trace_entities then
+ logs.report("xml","utfize, converting hex entity &#x%s; into %s",str,c)
+ end
+ else
+ if trace_entities then
+ logs.report("xml","found entity &#x%s;",str)
+ end
+ h = "&#" .. str .. ";"
+ end
+ hcache[str] = h
+ end
+ return h
+end
+local function handle_dec_entity(str)
+ local d = dcache[str]
+ if not d then
+ if utfize then
+ local n = tonumber(str)
+ d = (n and utfchar(n)) or xml.unknown_dec_entity_format(str) or ""
+ if not n then
+ logs.report("xml","utfize, ignoring dec entity &#%s;",str)
+ elseif trace_entities then
+ logs.report("xml","utfize, converting dec entity &#%s; into %s",str,c)
+ end
+ else
+ if trace_entities then
+ logs.report("xml","found entity &#%s;",str)
+ end
+ d = "&" .. str .. ";"
+ end
+ dcache[str] = d
+ end
+ return d
+end
+local function handle_any_entity(str)
+ if resolve then
+ local a = entities[str] -- per instance !
+ if not a then
+ a = acache[str]
+ if not a then
+ if trace_entities then
+ logs.report("xml","ignoring entity &%s;",str)
+ else
+ -- can be defined in a global mapper and intercepted elsewhere
+ -- as happens in lxml-tex.lua
+ end
+ a = xml.unknown_any_entity_format(str) or ""
+ acache[str] = a
+ end
+ elseif trace_entities then
+ if not acache[str] then
+ logs.report("xml","converting entity &%s; into %s",str,r)
+ acache[str] = a
+ end
+ end
+ return a
+ else
+ local a = acache[str]
+ if not a then
+ if trace_entities then
+ logs.report("xml","found entity &%s;",str)
+ end
+ a = "&" .. str .. ";"
+ acache[str] = a
+ end
+ return a
+ end
+end
+
+local P, S, R, C, V, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cs
local space = S(' \r\n\t')
local open = P('<')
@@ -289,6 +356,7 @@ local dquote = S('"')
local equal = P('=')
local slash = P('/')
local colon = P(':')
+local semicolon = P(';')
local ampersand = P('&')
local valid = R('az', 'AZ', '09') + S('_-.')
local name_yes = C(valid^1) * colon * C(valid^1)
@@ -299,15 +367,36 @@ local utfbom = P('\000\000\254\255') + P('\255\254\000\000') +
P('\255\254') + P('\254\255') + P('\239\187\191') -- no capture
local spacing = C(space^0)
-local justtext = C((1-open)^1)
+
+local entitycontent = (1-open-semicolon)^0
+local entity = ampersand/"" * (
+ P("#")/"" * (
+ P("x")/"" * (entitycontent/handle_hex_entity) +
+ (entitycontent/handle_dec_entity)
+ ) + (entitycontent/handle_any_entity)
+ ) * (semicolon/"")
+
+local text_unparsed = C((1-open)^1)
+local text_parsed = Cs(((1-open-ampersand)^1 + entity)^1)
+
local somespace = space^1
local optionalspace = space^0
local value = (squote * C((1 - squote)^0) * squote) + (dquote * C((1 - dquote)^0) * dquote) -- ampersand and < also invalid in value
-local attribute = (somespace * name * optionalspace * equal * optionalspace * value) / add_attribute
-local attributes = attribute^0
-local text = justtext / add_text
+local whatever = space * name * optionalspace * equal
+local wrongvalue = C(P(1-whatever-close)^1 + P(1-close)^1) / attribute_value_error
+
+local attributevalue = value + wrongvalue
+
+local attribute = (somespace * name * optionalspace * equal * optionalspace * attributevalue) / add_attribute
+----- attributes = (attribute)^0
+
+local endofattributes = slash * close + close -- recovery of flacky html
+local attributes = (attribute + somespace^-1 * (((1-endofattributes)^1)/attribute_specification_error))^0
+
+local parsedtext = text_parsed / add_text
+local unparsedtext = text_unparsed / add_text
local balanced = P { "[" * ((1 - S"[]") + V(1))^0 * "]" } -- taken from lpeg manual, () example
local emptyelement = (spacing * open * name * attributes * optionalspace * slash * close) / add_empty
@@ -360,25 +449,34 @@ local doctype = (spacing * begindoctype * somedoctype * enddoct
-- local cdata = (lpeg.Cc("@cd@") * spacing * begincdata * somecdata * endcdata ) / add_special
-- local doctype = (lpeg.Cc("@dt@") * spacing * begindoctype * somedoctype * enddoctype ) / add_special
-local trailer = space^0 * (justtext/set_message)^0
+local trailer = space^0 * (text_unparsed/set_message)^0
-- comment + emptyelement + text + cdata + instruction + V("parent"), -- 6.5 seconds on 40 MB database file
-- text + comment + emptyelement + cdata + instruction + V("parent"), -- 5.8
-- text + V("parent") + emptyelement + comment + cdata + instruction, -- 5.5
-local grammar = P { "preamble",
+local grammar_parsed_text = P { "preamble",
preamble = utfbom^0 * instruction^0 * (doctype + comment + instruction)^0 * V("parent") * trailer,
parent = beginelement * V("children")^0 * endelement,
- children = text + V("parent") + emptyelement + comment + cdata + instruction,
+ children = parsedtext + V("parent") + emptyelement + comment + cdata + instruction,
}
--- todo: xml.new + properties like entities and strip and such (store in root)
+local grammar_unparsed_text = P { "preamble",
+ preamble = utfbom^0 * instruction^0 * (doctype + comment + instruction)^0 * V("parent") * trailer,
+ parent = beginelement * V("children")^0 * endelement,
+ children = unparsedtext + V("parent") + emptyelement + comment + cdata + instruction,
+}
-function xml.convert(data, no_root, strip_cm_and_dt, given_entities, parent_root) -- maybe use table met k/v (given_entities may disapear)
- strip = strip_cm_and_dt or xml.strip_cm_and_dt
- stack, top, at, xmlns, errorstr, result, entities = {}, {}, {}, {}, nil, nil, given_entities or {}
- if parent_root then
- mt = getmetatable(parent_root)
+local function xmlconvert(data, settings)
+ settings = settings or { } -- no_root strip_cm_and_dt given_entities parent_root error_handler
+ strip = settings.strip_cm_and_dt
+ utfize = settings.utfize_entities
+ resolve = settings.resolve_entities
+ cleanup = settings.text_cleanup
+ stack, top, at, xmlns, errorstr, result, entities = {}, {}, {}, {}, nil, nil, settings.entities or {}
+ reported_attribute_errors = { }
+ if settings.parent_root then
+ mt = getmetatable(settings.parent_root)
else
initialize_mt(top)
end
@@ -387,20 +485,36 @@ function xml.convert(data, no_root, strip_cm_and_dt, given_entities, parent_root
dt = top.dt
if not data or data == "" then
errorstr = "empty xml file"
- elseif not grammar:match(data) then
- errorstr = "invalid xml file"
+ elseif utfize or resolve then
+ if grammar_parsed_text:match(data) then
+ errorstr = ""
+ else
+ errorstr = "invalid xml file - parsed text"
+ end
else
- errorstr = ""
+ if grammar_unparsed_text:match(data) then
+ errorstr = ""
+ else
+ errorstr = "invalid xml file - unparsed text"
+ end
end
if errorstr and errorstr ~= "" then
- result = { dt = { { ns = "", tg = "error", dt = { errorstr }, at={}, er = true } }, error = true }
+ result = { dt = { { ns = "", tg = "error", dt = { errorstr }, at={}, er = true } } }
setmetatable(stack, mt)
- if xml.error_handler then xml.error_handler("load",errorstr) end
+ local error_handler = settings.error_handler
+ if error_handler == false then
+ -- no error message
+ else
+ error_handler = error_handler or xml.error_handler
+ if error_handler then
+ xml.error_handler("load",errorstr)
+ end
+ end
else
result = stack[1]
end
- if not no_root then
- result = { special = true, ns = "", tg = '@rt@', dt = result.dt, at={}, entities = entities }
+ if not settings.no_root then
+ result = { special = true, ns = "", tg = '@rt@', dt = result.dt, at={}, entities = entities, settings = settings }
setmetatable(result, mt)
local rdt = result.dt
for k=1,#rdt do
@@ -411,9 +525,14 @@ function xml.convert(data, no_root, strip_cm_and_dt, given_entities, parent_root
end
end
end
+ if errorstr and errorstr ~= "" then
+ result.error = true
+ end
return result
end
+xml.convert = xmlconvert
+
--[[ldx--
<p>Packaging data in an xml like table is done with the following
function. Maybe it will go away (when not used).</p>
@@ -446,16 +565,16 @@ function xml.load(filename)
if type(filename) == "string" then
local f = io.open(filename,'r')
if f then
- local root = xml.convert(f:read("*all"))
+ local root = xmlconvert(f:read("*all"))
f:close()
return root
else
- return xml.convert("")
+ return xmlconvert("")
end
elseif filename then -- filehandle
- return xml.convert(filename:read("*all"))
+ return xmlconvert(filename:read("*all"))
else
- return xml.convert("")
+ return xmlconvert("")
end
end
@@ -464,9 +583,11 @@ end
valid trees, which is what the next function does.</p>
--ldx]]--
+local no_root = { no_root = true }
+
function xml.toxml(data)
if type(data) == "string" then
- local root = { xml.convert(data,true) }
+ local root = { xmlconvert(data,no_root) }
return (#root > 1 and root) or root[1]
else
return data
@@ -511,222 +632,305 @@ alternative.</p>
-- todo: add <?xml version='1.0' standalone='yes'?> when not present
-local fallbackhandle = (tex and tex.sprint) or io.write
-
-local serializer
-
-function xml.setserializer(f)
- serializer = f
-end
-
-local function serialize(e, handle, textconverter, attributeconverter, specialconverter, nocommands)
- if not e then
- return
- elseif not nocommands then
- local ec = e.command
- if ec ~= nil then -- we can have all kind of types
- if e.special then
- local etg, edt = e.tg, e.dt
- local spc = specialconverter and specialconverter[etg]
- if spc then
- local result = spc(edt[1])
- if result then
- handle(result)
- return
- else
- -- no need to handle any further
- end
- end
- end
- if serializer then
- serializer(e,ec)
- return
+function xml.checkbom(root) -- can be made faster
+ if root.ri then
+ local dt, found = root.dt, false
+ for k=1,#dt do
+ local v = dt[k]
+ if type(v) == "table" and v.special and v.tg == "@pi" and find(v.dt,"xml.*version=") then
+ found = true
+ break
end
end
+ if not found then
+ insert(dt, 1, { special=true, ns="", tg="@pi@", dt = { "xml version='1.0' standalone='yes'"} } )
+ insert(dt, 2, "\n" )
+ end
end
- handle = handle or fallbackhandle
- local etg = e.tg
- if etg then
- if e.special then
- local edt = e.dt
- local spc = specialconverter and specialconverter[etg]
- if spc then
- local result = spc(edt[1])
- if result then
- handle(result)
+end
+
+--[[ldx--
+<p>At the cost of some 25% runtime overhead you can first convert the tree to a string
+and then handle the lot.</p>
+--ldx]]--
+
+-- new experimental reorganized serialize
+
+local function verbose_element(e,handlers)
+ local handle = handlers.handle
+ local serialize = handlers.serialize
+ local ens, etg, eat, edt, ern = e.ns, e.tg, e.at, e.dt, e.rn
+ local ats = eat and next(eat) and { }
+ if ats then
+ for k,v in next, eat do
+ ats[#ats+1] = format('%s=%q',k,v)
+ end
+ end
+ if ern and trace_remap and ern ~= ens then
+ ens = ern
+ end
+ if ens ~= "" then
+ if edt and #edt > 0 then
+ if ats then
+ handle("<",ens,":",etg," ",concat(ats," "),">")
+ else
+ handle("<",ens,":",etg,">")
+ end
+ for i=1,#edt do
+ local e = edt[i]
+ if type(e) == "string" then
+ handle(e)
else
- -- no need to handle any further
+ serialize(e,handlers)
end
- elseif etg == "@pi@" then
- -- handle(format("<?%s?>",edt[1]))
- handle("<?" .. edt[1] .. "?>")
- elseif etg == "@cm@" then
- -- handle(format("<!--%s-->",edt[1]))
- handle("<!--" .. edt[1] .. "-->")
- elseif etg == "@cd@" then
- -- handle(format("<![CDATA[%s]]>",edt[1]))
- handle("<![CDATA[" .. edt[1] .. "]]>")
- elseif etg == "@dt@" then
- -- handle(format("<!DOCTYPE %s>",edt[1]))
- handle("<!DOCTYPE " .. edt[1] .. ">")
- elseif etg == "@rt@" then
- serialize(edt,handle,textconverter,attributeconverter,specialconverter,nocommands)
end
+ handle("</",ens,":",etg,">")
else
- local ens, eat, edt, ern = e.ns, e.at, e.dt, e.rn
- local ats = eat and next(eat) and { } -- type test maybe faster
if ats then
- if attributeconverter then
- for k,v in next, eat do
- ats[#ats+1] = format('%s=%q',k,attributeconverter(v))
- end
- else
- for k,v in next, eat do
- ats[#ats+1] = format('%s=%q',k,v)
- end
- end
+ handle("<",ens,":",etg," ",concat(ats," "),"/>")
+ else
+ handle("<",ens,":",etg,"/>")
end
- if ern and trace_remap and ern ~= ens then
- ens = ern
+ end
+ else
+ if edt and #edt > 0 then
+ if ats then
+ handle("<",etg," ",concat(ats," "),">")
+ else
+ handle("<",etg,">")
end
- if ens ~= "" then
- if edt and #edt > 0 then
- if ats then
- -- handle(format("<%s:%s %s>",ens,etg,concat(ats," ")))
- handle("<" .. ens .. ":" .. etg .. " " .. concat(ats," ") .. ">")
- else
- -- handle(format("<%s:%s>",ens,etg))
- handle("<" .. ens .. ":" .. etg .. ">")
- end
- for i=1,#edt do
- local e = edt[i]
- if type(e) == "string" then
- if textconverter then
- handle(textconverter(e))
- else
- handle(e)
- end
- else
- serialize(e,handle,textconverter,attributeconverter,specialconverter,nocommands)
- end
- end
- -- handle(format("</%s:%s>",ens,etg))
- handle("</" .. ens .. ":" .. etg .. ">")
+ for i=1,#edt do
+ local ei = edt[i]
+ if type(ei) == "string" then
+ handle(ei)
else
- if ats then
- -- handle(format("<%s:%s %s/>",ens,etg,concat(ats," ")))
- handle("<" .. ens .. ":" .. etg .. " " .. concat(ats," ") .. "/>")
- else
- -- handle(format("<%s:%s/>",ens,etg))
- handle("<" .. ens .. ":" .. etg .. "/>")
- end
+ serialize(ei,handlers)
end
+ end
+ handle("</",etg,">")
+ else
+ if ats then
+ handle("<",etg," ",concat(ats," "),"/>")
else
- if edt and #edt > 0 then
- if ats then
- -- handle(format("<%s %s>",etg,concat(ats," ")))
- handle("<" .. etg .. " " .. concat(ats," ") .. ">")
- else
- -- handle(format("<%s>",etg))
- handle("<" .. etg .. ">")
- end
- for i=1,#edt do
- local ei = edt[i]
- if type(ei) == "string" then
- if textconverter then
- handle(textconverter(ei))
- else
- handle(ei)
- end
- else
- serialize(ei,handle,textconverter,attributeconverter,specialconverter,nocommands)
- end
- end
- -- handle(format("</%s>",etg))
- handle("</" .. etg .. ">")
- else
- if ats then
- -- handle(format("<%s %s/>",etg,concat(ats," ")))
- handle("<" .. etg .. " " .. concat(ats," ") .. "/>")
- else
- -- handle(format("<%s/>",etg))
- handle("<" .. etg .. "/>")
- end
- end
+ handle("<",etg,"/>")
end
end
- elseif type(e) == "string" then
- if textconverter then
- handle(textconverter(e))
+ end
+end
+
+local function verbose_pi(e,handlers)
+ handlers.handle("<?",e.dt[1],"?>")
+end
+
+local function verbose_comment(e,handlers)
+ handlers.handle("<!--",e.dt[1],"-->")
+end
+
+local function verbose_cdata(e,handlers)
+ handlers.handle("<![CDATA[", e.dt[1],"]]>")
+end
+
+local function verbose_doctype(e,handlers)
+ handlers.handle("<!DOCTYPE ",e.dt[1],">")
+end
+
+local function verbose_root(e,handlers)
+ handlers.serialize(e.dt,handlers)
+end
+
+local function verbose_text(e,handlers)
+ handlers.handle(e)
+end
+
+local function verbose_document(e,handlers)
+ local serialize = handlers.serialize
+ local functions = handlers.functions
+ for i=1,#e do
+ local ei = e[i]
+ if type(ei) == "string" then
+ functions["@tx@"](ei,handlers)
else
- handle(e)
+ serialize(ei,handlers)
end
- else
- for i=1,#e do
- local ei = e[i]
- if type(ei) == "string" then
- if textconverter then
- handle(textconverter(ei))
- else
- handle(ei)
- end
- else
- serialize(ei,handle,textconverter,attributeconverter,specialconverter,nocommands)
- end
+ end
+end
+
+local function serialize(e,handlers,...)
+ local initialize = handlers.initialize
+ local finalize = handlers.finalize
+ local functions = handlers.functions
+ if initialize then
+ local state = initialize(...)
+ if not state == true then
+ return state
end
end
+ local etg = e.tg
+ if etg then
+ (functions[etg] or functions["@el@"])(e,handlers)
+ -- elseif type(e) == "string" then
+ -- functions["@tx@"](e,handlers)
+ else
+ functions["@dc@"](e,handlers)
+ end
+ if finalize then
+ return finalize()
+ end
end
-xml.serialize = serialize
+local function xserialize(e,handlers)
+ local functions = handlers.functions
+ local etg = e.tg
+ if etg then
+ (functions[etg] or functions["@el@"])(e,handlers)
+ -- elseif type(e) == "string" then
+ -- functions["@tx@"](e,handlers)
+ else
+ functions["@dc@"](e,handlers)
+ end
+end
-function xml.checkbom(root) -- can be made faster
- if root.ri then
- local dt, found = root.dt, false
- for k=1,#dt do
- local v = dt[k]
- if type(v) == "table" and v.special and v.tg == "@pi" and find(v.dt,"xml.*version=") then
- found = true
- break
+local handlers = { }
+
+local function newhandlers(settings)
+ local t = table.copy(handlers.verbose or { }) -- merge
+ if settings then
+ for k,v in next, settings do
+ if type(v) == "table" then
+ tk = t[k] if not tk then tk = { } t[k] = tk end
+ for kk,vv in next, v do
+ tk[kk] = vv
+ end
+ else
+ t[k] = v
end
end
- if not found then
- insert(dt, 1, { special=true, ns="", tg="@pi@", dt = { "xml version='1.0' standalone='yes'"} } )
- insert(dt, 2, "\n" )
+ if settings.name then
+ handlers[settings.name] = t
end
end
+ return t
+end
+
+local nofunction = function() end
+
+function xml.sethandlersfunction(handler,name,fnc)
+ handler.functions[name] = fnc or nofunction
+end
+
+function xml.gethandlersfunction(handler,name)
+ return handler.functions[name]
end
+function xml.gethandlers(name)
+ return handlers[name]
+end
+
+newhandlers {
+ name = "verbose",
+ initialize = false, -- faster than nil and mt lookup
+ finalize = false, -- faster than nil and mt lookup
+ serialize = xserialize,
+ handle = print,
+ functions = {
+ ["@dc@"] = verbose_document,
+ ["@dt@"] = verbose_doctype,
+ ["@rt@"] = verbose_root,
+ ["@el@"] = verbose_element,
+ ["@pi@"] = verbose_pi,
+ ["@cm@"] = verbose_comment,
+ ["@cd@"] = verbose_cdata,
+ ["@tx@"] = verbose_text,
+ }
+}
+
--[[ldx--
-<p>At the cost of some 25% runtime overhead you can first convert the tree to a string
-and then handle the lot.</p>
+<p>How you deal with saving data depends on your preferences. For a 40 MB database
+file the timing on a 2.3 Core Duo are as follows (time in seconds):</p>
+
+<lines>
+1.3 : load data from file to string
+6.1 : convert string into tree
+5.3 : saving in file using xmlsave
+6.8 : converting to string using xml.tostring
+3.6 : saving converted string in file
+</lines>
+
+<p>Beware, these were timing with the old routine but measurements will not be that
+much different I guess.</p>
--ldx]]--
-function xml.tostring(root) -- 25% overhead due to collecting
+-- maybe this will move to lxml-xml
+
+local result
+
+local xmlfilehandler = newhandlers {
+ name = "file",
+ initialize = function(name) result = io.open(name,"wb") return result end,
+ finalize = function() result:close() return true end,
+ handle = function(...) result:write(...) end,
+}
+
+-- no checking on writeability here but not faster either
+--
+-- local xmlfilehandler = newhandlers {
+-- initialize = function(name) io.output(name,"wb") return true end,
+-- finalize = function() io.close() return true end,
+-- handle = io.write,
+-- }
+
+
+function xml.save(root,name)
+ serialize(root,xmlfilehandler,name)
+end
+
+local result
+
+local xmlstringhandler = newhandlers {
+ name = "string",
+ initialize = function() result = { } return result end,
+ finalize = function() return concat(result) end,
+ handle = function(...) result[#result+1] = concat { ... } end
+}
+
+local function xmltostring(root) -- 25% overhead due to collecting
if root then
if type(root) == 'string' then
return root
- elseif next(root) then -- next is faster than type (and >0 test)
- local result = { }
- serialize(root,function(s) result[#result+1] = s end) -- brrr, slow (direct printing is faster)
- return concat(result,"")
+ else -- if next(root) then -- next is faster than type (and >0 test)
+ return serialize(root,xmlstringhandler) or ""
end
end
return ""
end
+local function xmltext(root) -- inline
+ return (root and xmltostring(root)) or ""
+end
+
+function initialize_mt(root)
+ mt = { __tostring = xmltext, __index = root }
+end
+
+xml.defaulthandlers = handlers
+xml.newhandlers = newhandlers
+xml.serialize = serialize
+xml.tostring = xmltostring
+xml.text = xmltext
+
--[[ldx--
<p>The next function operated on the content only and needs a handle function
that accepts a string.</p>
--ldx]]--
-function xml.string(e,handle)
+local function xmlstring(e,handle)
if not handle or (e.special and e.tg ~= "@rt@") then
-- nothing
elseif e.tg then
local edt = e.dt
if edt then
for i=1,#edt do
- xml.string(edt[i],handle)
+ xmlstring(edt[i],handle)
end
end
else
@@ -734,33 +938,16 @@ function xml.string(e,handle)
end
end
---[[ldx--
-<p>How you deal with saving data depends on your preferences. For a 40 MB database
-file the timing on a 2.3 Core Duo are as follows (time in seconds):</p>
-
-<lines>
-1.3 : load data from file to string
-6.1 : convert string into tree
-5.3 : saving in file using xmlsave
-6.8 : converting to string using xml.tostring
-3.6 : saving converted string in file
-</lines>
-
-<p>The save function is given below.</p>
---ldx]]--
-
-function xml.save(root,name)
- local f = io.open(name,"w")
- if f then
- xml.serialize(root,function(s) f:write(s) end)
- f:close()
- end
-end
+xml.string = xmlstring
--[[ldx--
<p>A few helpers:</p>
--ldx]]--
+function xml.parent(root)
+ return root.__p__
+end
+
function xml.body(root)
return (root.ri and root.dt[root.ri]) or root
end
@@ -773,34 +960,19 @@ function xml.content(root) -- bugged
return (root and root.dt and xml.tostring(root.dt)) or ""
end
-function xml.isempty(root, pattern)
- if pattern == "" or pattern == "*" then
- pattern = nil
- end
- if pattern then
- -- todo
- return false
- else
- return not root or not root.dt or #root.dt == 0 or root.dt == ""
- end
-end
-
--[[ldx--
<p>The next helper erases an element but keeps the table as it is,
and since empty strings are not serialized (effectively) it does
not harm. Copying the table would take more time. Usage:</p>
-
-<typing>
-dt[k] = xml.empty() or xml.empty(dt,k)
-</typing>
--ldx]]--
-function xml.empty(dt,k)
- if dt and k then
- dt[k] = ""
- return dt[k]
- else
- return ""
+function xml.erase(dt,k)
+ if dt then
+ if k then
+ dt[k] = ""
+ else for k=1,#dt do
+ dt[1] = { "" }
+ end end
end
end
diff --git a/tex/context/base/lxml-tex.lua b/tex/context/base/lxml-tex.lua
new file mode 100644
index 000000000..69f5b5116
--- /dev/null
+++ b/tex/context/base/lxml-tex.lua
@@ -0,0 +1,1309 @@
+if not modules then modules = { } end modules ['lxml-tst'] = {
+ version = 1.001,
+ comment = "companion to lxml-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+
+local utfchar = utf.char
+local concat, insert, remove, gsub, find = table.concat, table.insert, table.remove
+local format, sub, gsub, find = string.format, string.sub, string.gsub, string.find
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+
+if not tex and not tex.sprint then
+ tex = {
+ sprint = function(catcodes,...) texio.write(table.concat{...}) end,
+ print = function(catcodes,...) texio.write(table.concat{...}) end,
+ write = function( ...) texio.write(table.concat{...}) end,
+ }
+ commands = {
+ writestatus = logs.report
+ }
+ resolvers.loadbinfile = function(filename) return true, io.loaddata(filename) end
+end
+
+local texsprint, texprint, texwrite = tex.sprint, tex.print, tex.write
+local texcatcodes, ctxcatcodes, vrbcatcodes = tex.texcatcodes, tex.ctxcatcodes, tex.vrbcatcodes
+
+local xmlelements, xmlcollected, xmlsetproperty = xml.elements, xml.collected, xml.setproperty
+local xmlparseapply, xmlwithelements = xml.parse_apply, xml.withelements
+local xmlserialize, xmlcollect, xmlcontent = xml.serialize, xml.collect, xml.content
+local xmltostring = xml.tostring
+
+local variables = (interfaces and interfaces.variables) or { }
+
+local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
+
+local trace_setups = false trackers.register("lxml.setups", function(v) trace_setups = v end)
+local trace_loading = false trackers.register("lxml.loading", function(v) trace_loading = v end)
+local trace_access = false trackers.register("lxml.access", function(v) trace_access = v end)
+local trace_comments = false trackers.register("lxml.comments", function(v) trace_comments = v end)
+
+lxml = lxml or { }
+lxml.loaded = lxml.loaded or { }
+lxml.noffiles = 0
+lxml.nofconverted = 0
+
+local loaded = lxml.loaded
+
+-- print(contextdirective("context-mathml-directive function reduction yes "))
+-- print(contextdirective("context-mathml-directive function "))
+
+xml.defaultprotocol = "tex"
+
+local finalizers = xml.finalizers
+
+finalizers.xml = finalizers.xml or { }
+finalizers.tex = finalizers.tex or { }
+
+-- this might look inefficient but it's actually rather efficient
+-- because we avoid tokenization of leading spaces and xml can be
+-- rather verbose (indented)
+
+local crlf = lpeg.P("\r\n")
+local cr = lpeg.P("\r")
+local lf = lpeg.P("\n")
+local newline = crlf + cr + lf
+local space = lpeg.S(" \t\f\v")
+local ampersand = lpeg.P("&")
+local semicolon = lpeg.P(";")
+local spacing = newline * space^0
+local content = lpeg.C((1-spacing-ampersand)^1)
+local verbose = lpeg.C((1-(space+newline))^1)
+local entity = ampersand * lpeg.C((1-semicolon)^1) * semicolon
+
+local xmltextcapture = (
+ space^0 * newline^2 * lpeg.Cc("") / texprint + -- better ^-2 ?
+ space^0 * newline * space^0 * lpeg.Cc(" ") / texsprint +
+ content / texsprint + -- current catcodes regime is notcatcodes
+ entity / xml.resolved_entity
+)^0
+
+local forceraw, rawroot = false, nil
+
+function lxml.startraw()
+ forceraw = true
+end
+
+function lxml.stopraw()
+ forceraw = false
+end
+
+function lxml.rawroot()
+ return rawroot
+end
+
+--~ function lxml.rawpath(rootid)
+--~ if rawroot and type(rawroot) == "table" then
+--~ local text, path, rp
+--~ if not rawroot.dt then
+--~ text, path, rp = "text", "", rawroot[0]
+--~ else
+--~ path, rp = "tree", "", rawroot.__p__
+--~ end
+--~ while rp do
+--~ local rptg = rp.tg
+--~ if rptg then
+--~ path = rptg .. "/" .. path
+--~ end
+--~ rp = rp.__p__
+--~ end
+--~ return { rootid, "/" .. path, text }
+--~ end
+--~ end
+
+-- cdata
+
+local linecommand = "\\obeyedline"
+local spacecommand = "\\obeyedspace" -- "\\strut\\obeyedspace"
+local beforecommand = ""
+local aftercommand = ""
+
+local xmlverbosecapture = (
+ newline / function( ) texsprint(texcatcodes,linecommand,"{}") end +
+ verbose / function(s) texsprint(vrbcatcodes,s) end +
+ space / function( ) texsprint(texcatcodes,spacecommand,"{}") end
+)^0
+
+local function toverbatim(str)
+ if beforecommand then texsprint(texcatcodes,beforecommand,"{}") end
+ xmlverbosecapture:match(str)
+ if aftercommand then texsprint(texcatcodes,aftercommand,"{}") end
+end
+
+function lxml.set_verbatim(before,after,obeyedline,obeyedspace)
+ beforecommand, aftercommand, linecommand, spacecommand = before, after, obeyedline, obeyedspace
+end
+
+local obeycdata = true
+
+function lxml.set_cdata()
+ obeycdata = true
+end
+
+function lxml.reset_cdata()
+ obeycdata = false
+end
+
+-- cdata and verbatim
+
+lxml.set_verbatim("\\xmlcdatabefore", "\\xmlcdataafter", "\\xmlcdataobeyedline", "\\xmlcdataobeyedspace")
+
+-- local capture = (space^0*newline)^0 * capture * (space+newline)^0 * -1
+
+function lxml.toverbatim(str)
+ if beforecommand then texsprint(texcatcodes,beforecommand,"{}") end
+ -- todo: add this to capture
+ str = gsub(str,"^[ \t]+[\n\r]+","")
+ str = gsub(str,"[ \t\n\r]+$","")
+ xmlverbosecapture:match(str)
+ if aftercommand then texsprint(texcatcodes,aftercommand,"{}") end
+end
+
+-- storage
+
+function lxml.store(id,root,filename)
+ loaded[id] = root
+ xmlsetproperty(root,"name",id)
+ if filename then
+ xmlsetproperty(root,"filename",filename)
+ end
+end
+
+local splitter = lpeg.C((1-lpeg.P(":"))^1) * lpeg.P("::") * lpeg.C(lpeg.P(1)^1)
+
+lxml.idsplitter = splitter
+
+function lxml.splitid(id)
+ local d, i = splitter:match(id)
+ if d then
+ return d, i
+ else
+ return "", id
+ end
+end
+
+local function get_id(id, qualified)
+ if id then
+ local lid = loaded[id]
+ if lid then
+ return lid
+ elseif type(id) == "table" then
+ return id
+ else
+ local d, i = splitter:match(id)
+ if d then
+ local ld = loaded[d]
+ if ld then
+ local ldi = ld.index
+ if ldi then
+ local root = ldi[tonumber(i)]
+ if root then
+ if qualified then -- we need this else two args that confuse others
+ return root, d
+ else
+ return root
+ end
+ elseif trace_access then
+ logs.report("lxml","'%s' has no index entry '%s'",d,i)
+ end
+ elseif trace_access then
+ logs.report("lxml","'%s' has no index",d)
+ end
+ elseif trace_access then
+ logs.report("lxml","'%s' is not loaded",d)
+ end
+ elseif trace_access then
+ logs.report("lxml","'%s' is not loaded",i)
+ end
+ end
+ elseif trace_access then
+ logs.report("lxml","invalid id (nil)")
+ end
+end
+
+lxml.id = get_id
+lxml.get_id = get_id
+
+function lxml.root(id)
+ return loaded[id]
+end
+
+-- index
+
+local nofindices = 0
+
+local function addindex(name,check_sum,force)
+ local root = get_id(name)
+ if root and (not root.index or force) then -- weird, only called once
+ local n, index, maxindex, check = 0, root.index or { }, root.maxindex or 0, root.check or { }
+ local function nest(root)
+ local dt = root.dt
+ if not root.ix then
+ maxindex = maxindex + 1
+ root.ix = maxindex
+ check[maxindex] = root.tg -- still needed ?
+ index[maxindex] = root
+ n = n + 1
+ end
+ if dt then
+ for k=1,#dt do
+ local dk = dt[k]
+ if type(dk) == "table" then
+ nest(dk)
+ end
+ end
+ end
+ end
+ nest(root)
+ nofindices = nofindices + n
+ --
+ if type(name) ~= "string" then
+ name = "unknown"
+ end
+ root.index = index
+ root.maxindex = maxindex
+ if trace_access then
+ logs.report("lxml","%s indexed, %s nodes",tostring(name),maxindex)
+ end
+ end
+end
+
+lxml.addindex = addindex
+
+-- another cache
+
+local function lxmlparseapply(id,pattern) -- better inline, saves call
+ return xmlparseapply({ get_id(id) }, pattern)
+end
+
+lxml.filter = lxmlparseapply
+
+lxml["function"] = function(id,name)
+ local f = xml.functions[name]
+ return f and f(get_id(id))
+end
+
+-- rather new, indexed storage (backward refs), maybe i will merge this
+
+function lxml.checkindex(name)
+ local root = get_id(name)
+ return (root and root.index) or 0
+end
+
+function lxml.withindex(name,n,command) -- will change as name is always there now
+ local i, p = splitter:match(n)
+ if p then
+ texsprint(ctxcatcodes,"\\xmlw{",command,"}{",n,"}")
+ else
+ texsprint(ctxcatcodes,"\\xmlw{",command,"}{",name,"::",n,"}")
+ end
+end
+
+function lxml.getindex(name,n) -- will change as name is always there now
+ local i, p = splitter:match(n)
+ if p then
+ texsprint(ctxcatcodes,n)
+ else
+ texsprint(ctxcatcodes,name,"::",n)
+ end
+end
+
+-- loading (to be redone, no overload)
+
+xml.originalload = xml.originalload or xml.load
+
+local noffiles, nofconverted = 0, 0
+
+function xml.load(filename)
+ noffiles = noffiles + 1
+ nofconverted = nofconverted + 1
+ starttiming(xml)
+ local ok, data = resolvers.loadbinfile(filename)
+ local xmltable = xml.convert((ok and data) or "")
+ stoptiming(xml)
+ return xmltable
+end
+
+function lxml.convert(data,entities,compress)
+ local settings = { }
+ if compress and compress == variables.yes then
+ settings.strip_cm_and_dt = true
+ end
+ if entities and entities == variables.yes then
+ settings.utfize_entities = true
+ settings.resolve_entities = true
+ end
+ return xml.convert(data,settings)
+end
+
+function lxml.load(id,filename,compress,entities)
+ filename = commands.preparedfile(filename)
+ if trace_loading then
+ commands.writestatus("lxml","loading file '%s' as '%s'",filename,id)
+ end
+ -- local xmltable = xml.load(filename)
+ local ok, data = resolvers.loadbinfile(filename)
+ local xmltable = lxml.convert((ok and data) or "",compress,entities)
+ lxml.store(id,xmltable,filename)
+ return xmltable, filename
+end
+
+function lxml.register(id,xmltable,filename)
+ lxml.store(id,xmltable,filename)
+ return xmltable
+end
+
+function lxml.include(id,pattern,attribute,recurse)
+ starttiming(xml)
+ local root = get_id(id)
+ xml.include(root,pattern,attribute,recurse,function(filename)
+ if filename then
+ filename = commands.preparedfile(filename)
+ if file.dirname(filename) == "" and root.filename then
+ filename = file.join(file.dirname(root.filename),filename)
+ end
+ if trace_loading then
+ commands.writestatus("lxml","including file: %s",filename)
+ end
+ noffiles = noffiles + 1
+ nofconverted = nofconverted + 1
+ return resolvers.loadtexfile(filename) or ""
+ else
+ return ""
+ end
+ end)
+ stoptiming(xml)
+end
+
+function xml.getbuffer(name,compress,entities) -- we need to make sure that commands are processed
+ if not name or name == "" then
+ name = tex.jobname
+ end
+ nofconverted = nofconverted + 1
+ xmltostring(lxml.convert(concat(buffers.data[name] or {},""),compress,entities))
+end
+
+function lxml.loadbuffer(id,name,compress,entities)
+ if not name or name == "" then
+ name = tex.jobname
+ end
+ starttiming(xml)
+ nofconverted = nofconverted + 1
+ local xmltable = lxml.convert(buffers.collect(name or id,"\n"),compress,entities)
+ lxml.store(id,xmltable)
+ stoptiming(xml)
+ return xmltable, name or id
+end
+
+function lxml.loaddata(id,str,compress,entities)
+ starttiming(xml)
+ nofconverted = nofconverted + 1
+ local xmltable = lxml.convert(str or "",compress,entities)
+ lxml.store(id,xmltable)
+ stoptiming(xml)
+ return xmltable, id
+end
+
+function lxml.loadregistered(id)
+ return loaded[id], id
+end
+
+-- e.command:
+--
+-- string : setup
+-- true : text (no <self></self>)
+-- false : ignore
+-- function : call
+
+local function tex_doctype(e,handlers)
+ -- ignore
+end
+
+local function tex_comment(e,handlers)
+ if trace_comments then
+ logs.report("lxml","comment: %s",e.dt[1])
+ end
+end
+
+local default_element_handler = xml.gethandlers("verbose").functions["@el@"]
+
+local function tex_element(e,handlers)
+ local command = e.command
+ if command == nil then
+ default_element_handler(e,handlers)
+ elseif command == true then
+ -- text (no <self></self>) / so, no mkii fallback then
+ handlers.serialize(e.dt,handlers)
+ elseif command == false then
+ -- ignore
+ else
+ local tc = type(command)
+ if tc == "string" then
+ local rootname, ix = e.name, e.ix
+ if rootname then
+ if not ix then
+ addindex(rootname,false,true)
+ ix = e.ix
+ end
+ texsprint(ctxcatcodes,"\\xmlw{",command,"}{",rootname,"::",ix,"}")
+ else
+ logs.report("lxml", "fatal error: no index for '%s'",command)
+ texsprint(ctxcatcodes,"\\xmlw{",command,"}{",ix or 0,"}")
+ end
+ elseif tc == "function" then
+ command(e)
+ end
+ end
+end
+
+local pihandlers = { } xml.pihandlers = pihandlers
+
+local kind = lpeg.P("context-") * lpeg.C((1-lpeg.P("-"))^1) * lpeg.P("-directive")
+local space = lpeg.S(" \n\r")
+local spaces = space^0
+local class = lpeg.C((1-space)^0)
+local key = class
+local value = lpeg.C(lpeg.P(1-(space * -1))^0)
+
+local parser = kind * spaces * class * spaces * key * spaces * value
+
+pihandlers[#pihandlers+1] = function(str)
+-- local kind, class, key, value = parser:match(str)
+ if str then
+ local a, b, c, d = parser:match(str)
+ if d then
+ texsprint(ctxcatcodes,"\\xmlcontextdirective{",a",}{",b,"}{",c,"}{",d,"}")
+ end
+ end
+end
+
+local function tex_pi(e,handlers)
+ local str = e.dt[1]
+ for i=1,#pihandlers do
+ pihandlers[i](str)
+ end
+end
+
+local function tex_cdata(e,handlers)
+ if obeycdata then
+ toverbatim(e.dt[1])
+ end
+end
+
+local function tex_text(e,handlers)
+ xmltextcapture:match(e)
+end
+
+local function tex_handle(...)
+-- logs.report("lxml", "error while flushing: %s", concat { ... })
+ texsprint(...) -- notcatcodes is active anyway
+end
+
+local xmltexhandler = xml.newhandlers {
+ name = "tex",
+ handle = tex_handle,
+ functions = {
+ -- ["@dc@"] = tex_document,
+ ["@dt@"] = tex_doctype,
+ -- ["@rt@"] = tex_root,
+ ["@el@"] = tex_element,
+ ["@pi@"] = tex_pi,
+ ["@cm@"] = tex_comment,
+ ["@cd@"] = tex_cdata,
+ ["@tx@"] = tex_text,
+ }
+}
+
+function lxml.serialize(root)
+ xmlserialize(root,xmltexhandler)
+end
+
+function lxml.setaction(id,pattern,action)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ for c=1,#collected do
+ collected[c].command = action
+ end
+ end
+end
+
+local function sprint(root)
+ if root then
+ local tr = type(root)
+ if tr == "string" then -- can also be result of lpath
+ -- rawroot = false
+ xmltextcapture:match(root)
+ elseif tr == "table" then
+ if forceraw then
+ rawroot = root
+ texwrite(xmltostring(root))
+ else
+ xmlserialize(root,xmltexhandler)
+ end
+ end
+ end
+end
+
+local function tprint(root) -- we can move sprint inline
+ local tr = type(root)
+ if tr == "table" then
+ local n = #root
+ if n == 0 then
+ -- skip
+ else
+ for i=1,n do
+ sprint(root[i])
+ end
+ end
+ elseif tr == "string" then
+ xmltextcapture:match(root)
+ end
+end
+
+local function cprint(root) -- content
+ if not root then
+ -- rawroot = false
+ -- quit
+ elseif type(root) == 'string' then
+ -- rawroot = false
+ xmltextcapture:match(root)
+ else
+ local rootdt = root.dt
+ if forceraw then
+ rawroot = root
+ texwrite(xmltostring(rootdt or root))
+ else
+ xmlserialize(rootdt or root,xmltexhandler)
+ end
+ end
+end
+
+xml.sprint = sprint local xmlsprint = sprint -- redo these names
+xml.tprint = tprint local xmltprint = tprint
+xml.cprint = cprint local xmlcprint = cprint
+
+-- now we can flush
+
+function lxml.main(id)
+ xmlserialize(get_id(id),xmltexhandler) -- the real root (@rt@)
+end
+
+--~ -- lines (untested)
+--~
+--~ local buffer = { }
+--~
+--~ local xmllinescapture = (
+--~ newline^2 / function() buffer[#buffer+1] = "" end +
+--~ newline / function() buffer[#buffer] = buffer[#buffer] .. " " end +
+--~ content / function(s) buffer[#buffer] = buffer[#buffer] .. s end
+--~ )^0
+--~
+--~ local xmllineshandler = table.copy(xmltexhandler)
+--~
+--~ xmllineshandler.handle = function(...) xmllinescapture:match(concat{ ... }) end
+--~
+--~ function lines(root)
+--~ if not root then
+--~ -- rawroot = false
+--~ -- quit
+--~ elseif type(root) == 'string' then
+--~ -- rawroot = false
+--~ xmllinescapture:match(root)
+--~ elseif next(root) then -- tr == 'table'
+--~ xmlserialize(root,xmllineshandler)
+--~ end
+--~ end
+--~
+--~ function xml.lines(root) -- used at all?
+--~ buffer = { "" }
+--~ lines(root)
+--~ return result
+--~ end
+
+local function to_text(e)
+ if e.command == nil then
+ local etg = e.tg
+ if etg and e.special and etg ~= "@rt@" then
+ e.command = false -- i.e. skip
+ else
+ e.command = true -- i.e. no <self></self>
+ end
+ end
+end
+
+local function to_none(e)
+ if e.command == nil then
+ e.command = false -- i.e. skip
+ end
+end
+
+-- setups
+
+local setups = { }
+
+function lxml.set_command_to_text(id)
+ xmlwithelements(get_id(id),to_text)
+end
+
+function lxml.set_command_to_none(id)
+ xmlwithelements(get_id(id),to_none)
+end
+
+function lxml.installsetup(what,document,setup,where)
+ document = document or "*"
+ local sd = setups[document]
+ if not sd then sd = { } setups[document] = sd end
+ for k=1,#sd do
+ if sd[k] == setup then sd[k] = nil break end
+ end
+ if what == 1 then
+ if trace_loading then
+ commands.writestatus("lxml","prepending setup %s for %s",setup,document)
+ end
+ insert(sd,1,setup)
+ elseif what == 2 then
+ if trace_loading then
+ commands.writestatus("lxml","appending setup %s for %s",setup,document)
+ end
+ insert(sd,setup)
+ elseif what == 3 then
+ if trace_loading then
+ commands.writestatus("lxml","inserting setup %s for %s before %s",setup,document,where)
+ end
+ table.insert_before_value(sd,setup,where)
+ elseif what == 4 then
+ if trace_loading then
+ commands.writestatus("lxml","inserting setup %s for %s after %s",setup,document,where)
+ end
+ table.insert_after_value(sd,setup,where)
+ end
+end
+
+function lxml.flushsetups(...)
+ local done = { }
+ for _, document in ipairs({...}) do
+ local sd = setups[document]
+ if sd then
+ for k=1,#sd do
+ local v= sd[k]
+ if not done[v] then
+ if trace_loading then
+ commands.writestatus("lxml","applying setup %02i = %s to %s",k,v,document)
+ end
+ texsprint(ctxcatcodes,"\\directsetup{",v,"}")
+ done[v] = true
+ end
+ end
+ elseif trace_loading then
+ commands.writestatus("lxml","no setups for %s",document)
+ end
+ end
+end
+
+function lxml.resetsetups(document)
+ if trace_loading then
+ commands.writestatus("lxml","resetting all setups for %s",document)
+ end
+ setups[document] = { }
+end
+
+function lxml.removesetup(document,setup)
+ local s = setups[document]
+ if s then
+ for i=1,#s do
+ if s[i] == setup then
+ if trace_loading then
+ commands.writestatus("lxml","removing setup %s for %s",setup,document)
+ end
+ remove(t,i)
+ break
+ end
+ end
+ end
+end
+
+function lxml.setsetup(id,pattern,setup)
+ if not setup or setup == "" or setup == "*" or setup == "-" or setup == "+" then
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ if trace_setups then
+ for c=1, #collected do
+ local e = collected[c]
+ local ix = e.ix or 0
+ if setup == "-" then
+ e.command = false
+ logs.report("lxml","lpath matched (a) %5i: %s = %s -> skipped",c,ix,setup)
+ elseif setup == "+" then
+ e.command = true
+ logs.report("lxml","lpath matched (b) %5i: %s = %s -> text",c,ix,setup)
+ else
+ local tg = e.tg
+ if tg then -- to be sure
+ e.command = tg
+ local ns = e.rn or e.ns
+ if ns == "" then
+ logs.report("lxml","lpath matched (c) %5i: %s = %s -> %s",c,ix,tg,tg)
+ else
+ logs.report("lxml","lpath matched (d) %5i: %s = %s:%s -> %s",c,ix,ns,tg,tg)
+ end
+ end
+ end
+ end
+ else
+ for c=1, #collected do
+ local e = collected[c]
+ if setup == "-" then
+ e.command = false
+ elseif setup == "+" then
+ e.command = true
+ else
+ e.command = e.tg
+ end
+ end
+ end
+ elseif trace_setups then
+ logs.report("lxml","no lpath matches for %s",pattern)
+ end
+ else
+ local a, b = setup:match("^(.+:)([%*%-])$")
+ if a and b then
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ if trace_setups then
+ for c=1, #collected do
+ local e = collected[c]
+ local ns, tg, ix = e.rn or e.ns, e.tg, e.ix or 0
+ if b == "-" then
+ e.command = false
+ if ns == "" then
+ logs.report("lxml","lpath matched (e) %5i: %s = %s -> skipped",c,ix,tg)
+ else
+ logs.report("lxml","lpath matched (f) %5i: %s = %s:%s -> skipped",c,ix,ns,tg)
+ end
+ elseif b == "+" then
+ e.command = true
+ if ns == "" then
+ logs.report("lxml","lpath matched (g) %5i: %s = %s -> text",c,ix,tg)
+ else
+ logs.report("lxml","lpath matched (h) %5i: %s = %s:%s -> text",c,ix,ns,tg)
+ end
+ else
+ e.command = a .. tg
+ if ns == "" then
+ logs.report("lxml","lpath matched (i) %5i: %s = %s -> %s",c,ix,tg,e.command)
+ else
+ logs.report("lxml","lpath matched (j) %5i: %s = %s:%s -> %s",c,ix,ns,tg,e.command)
+ end
+ end
+ end
+ else
+ for c=1, #collected do
+ local e = collected[c]
+ if b == "-" then
+ e.command = false
+ elseif b == "+" then
+ e.command = true
+ else
+ e.command = a .. e.tg
+ end
+ end
+ end
+ elseif trace_setups then
+ logs.report("lxml","no lpath matches for %s",pattern)
+ end
+ else
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ if trace_setups then
+ for c=1, #collected do
+ local e = collected[c]
+ e.command = setup
+ local ns, tg, ix = e.rn or e.ns, e.tg, e.ix or 0
+ if ns == "" then
+ logs.report("lxml","lpath matched (k) %5i: %s = %s -> %s",c,ix,tg,setup)
+ else
+ logs.report("lxml","lpath matched (l) %5i: %s = %s:%s -> %s",c,ix,ns,tg,setup)
+ end
+ end
+ else
+ for c=1, #collected do
+ collected[c].command = setup
+ end
+ end
+ elseif trace_setups then
+ logs.report("lxml","no lpath matches for %s",pattern)
+ end
+ end
+ end
+end
+
+-- finalizers
+
+local finalizers = xml.finalizers.tex
+
+local function first(collected)
+ if collected then
+ xmlsprint(collected[1])
+ end
+end
+
+local function last(collected)
+ if collected then
+ xmlsprint(collected[#collected])
+ end
+end
+
+local function all(collected)
+ if collected then
+ for c=1,#collected do
+ xmlsprint(collected[c])
+ end
+ end
+end
+
+local function reverse(collected)
+ if collected then
+ for c=#collected,1,-1 do
+ xmlsprint(collected[c])
+ end
+ end
+end
+
+local function count(collected)
+ texwrite((collected and #collected) or 0)
+end
+
+local function position(collected,n)
+ if collected then
+ n = tonumber(n) or 0
+ if n < 0 then
+ n = #collected + n + 1
+ end
+ if n > 0 then
+ xmlsprint(collected[n])
+ end
+ end
+end
+
+local function index(collected,n)
+ if collected then
+ n = tonumber(n) or 0
+ if n < 0 then
+ n = #collected + n + 1
+ end
+ if n > 0 then
+ texwrite(collected[n].ni or 0)
+ end
+ end
+end
+
+local function command(collected,cmd)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ local ix = e.ix
+ if not ix then
+ lxml.addindex(e.name,false,true)
+ ix = e.ix
+ end
+ texsprint(ctxcatcodes,"\\xmlw{",cmd,"}{",e.name,"::",ix,"}")
+ end
+ end
+end
+
+local function attribute(collected,a,default)
+ if collected then
+ local at = collected[1].at
+ local str = (at and at[a]) or default
+ if str and str ~= "" then
+ texsprint(ctxcatcodes,str)
+ end
+ elseif default then
+ texsprint(ctxcatcodes,default)
+ end
+end
+
+local function chainattribute(collected,arguments) -- todo: optional levels
+ if collected then
+ local e = collected[1]
+ while e do
+ local at = e.at
+ if at then
+ local a = at[arguments]
+ if a then
+ texsprint(ctxcatcodes,a)
+ end
+ else
+ break -- error
+ end
+ e = e.__p__
+ end
+ end
+end
+
+local function text(collected)
+ if collected then
+ local nc = #collected
+ if nc == 1 then -- hardly any gain so this will go
+ cprint(collected[1])
+ else for c=1,nc do
+ cprint(collected[c])
+ end end
+ end
+end
+
+local function number(collected)
+ if collected then
+ local n = 0
+ for c=1,#collected do
+ n = n + tonumber(collected[c].dt[1] or 0)
+ end
+ texwrite(n)
+ end
+end
+
+local function concatrange(collected,start,stop,separator,lastseparator) -- test this on mml
+ if collected then
+ local nofcollected = #collected
+ local separator = separator or ""
+ local lastseparator = lastseparator or separator or ""
+ start, stop = (start == "" and 1) or tonumber(start) or 1, (stop == "" and nofcollected) or tonumber(stop) or nofcollected
+ if stop < 0 then stop = nofcollected + stop end -- -1 == last-1
+ for i=start,stop do
+ xmlsprint(collected[i])
+ if i == nofcollected then
+ -- nothing
+ elseif i == nofcollected-1 and lastseparator ~= "" then
+ texsprint(ctxcatcodes,lastseparator)
+ elseif separator ~= "" then
+ texsprint(ctxcatcodes,separator)
+ end
+ end
+ end
+end
+
+local function concat(collected,separator,lastseparator) -- test this on mml
+ concatrange(collected,false,false,separator,lastseparator)
+end
+
+finalizers.first = first
+finalizers.last = last
+finalizers.all = all
+finalizers.reverse = reverse
+finalizers.count = count
+finalizers.command = command
+finalizers.attribute = attribute
+finalizers.text = text
+finalizers.position = position
+finalizers.index = index
+finalizers.concat = concat
+finalizers.concatrange = concatrange
+finalizers.chainattribute = chainattribute
+finalizers.default = all -- !!
+
+local concat = table.concat
+
+function finalizers.tag(root,pattern,n)
+ if collected then
+ local c
+ if n == 0 or not n then
+ c = collected[1]
+ elseif n > 1 then
+ c = collected[n]
+ else
+ c = collected[#collected-n+1]
+ end
+ if c then
+ texsprint(c.tg)
+ end
+ end
+end
+
+function finalizers.name(root,pattern,n)
+ if collected then
+ local c
+ if n == 0 or not n then
+ c = collected[1]
+ elseif n > 1 then
+ c = collected[n]
+ else
+ c = collected[#collected-n+1]
+ end
+ if c then
+ if c.ns ~= "" then
+ texsprint(c.tg)
+ else
+ texsprint(c.ns,":",c.tg)
+ end
+ end
+ end
+end
+
+function finalizers.tags(root,pattern,nonamespace)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ local ns, tg = e.ns, e.tg
+ if nonamespace or ns == "" then
+ texsprint(tg)
+ else
+ texsprint(ns,":",tg)
+ end
+ end
+ end
+end
+
+--
+
+local function verbatim(id,before,after)
+ local root = get_id(id)
+ if root then
+ if before then texsprint(ctxcatcodes,before,"[",root.tg or "?","]") end
+ lxml.toverbatim(xmltostring(root.dt))
+ if after then texsprint(ctxcatcodes,after) end
+ end
+end
+function lxml.inlineverbatim(id)
+ verbatim(id,"\\startxmlinlineverbatim","\\stopxmlinlineverbatim")
+end
+function lxml.displayverbatim(id)
+ verbatim(id,"\\startxmldisplayverbatim","\\stopxmldisplayverbatim")
+end
+
+lxml.verbatim = verbatim
+
+-- helpers
+
+function lxml.first(id,pattern)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ first(collected)
+ end
+end
+
+function lxml.last(id,pattern)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ last(collected)
+ end
+end
+
+function lxml.all(id,pattern)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ all(collected)
+ end
+end
+
+function lxml.count(id,pattern)
+ -- always needs to produce a result so no test here
+ count(lxmlparseapply(id,pattern))
+end
+
+function lxml.attribute(id,pattern,a,default)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ attribute(collected,a,default)
+ end
+end
+
+function lxml.text(id,pattern)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ text(collected)
+ end
+end
+
+function lxml.raw(id,pattern) -- the content, untouched by commands
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ texsprint(xmltostring(collected[1].dt))
+ end
+end
+
+function lxml.position(id,pattern,n)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ position(collected,n)
+ end
+end
+
+function lxml.chainattribute(id,pattern,a,default)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ chainattribute(collected,a,default)
+ end
+end
+
+function lxml.concatrange(id,pattern,start,stop,separator,lastseparator) -- test this on mml
+ concatrange(lxmlparseapply(id,pattern),start,stop,separator,lastseparator)
+end
+
+function lxml.concat(id,pattern,separator,lastseparator)
+ concatrange(lxmlparseapply(id,pattern),false,false,separator,lastseparator)
+end
+
+function lxml.element(id,n)
+ position(lxmlparseapply(id,"/*"),n)
+end
+
+lxml.index = lxml.position
+
+-- fast direct ones
+
+function lxml.content(root) -- bugged, does not print
+ local root = get_id(id)
+ local content = root and root.dt and xmltostring(root.dt)
+ if content then
+ texsprint(content)
+ end
+end
+
+function lxml.pos(id)
+ local root = get_id(id)
+ texwrite((root and root.ni) or 0)
+end
+
+function lxml.att(id,a,default)
+ local root = get_id(id)
+ if root then
+ local at = root.at
+ local str = (at and at[a]) or default
+ if str and str ~= "" then
+ texsprint(ctxcatcodes,str)
+ end
+ elseif default then
+ texsprint(ctxcatcodes,default)
+ end
+end
+
+function lxml.name(id) -- or remapped name? -> lxml.info, combine
+ local r = get_id(id)
+ local ns = r.rn or r.ns or ""
+ if ns ~= "" then
+ texsprint(ns,":",r.tg)
+ else
+ texsprint(r.tg)
+ end
+end
+
+function lxml.tag(id) -- tag vs name -> also in l-xml tag->name
+ texsprint(get_id(id).tg or "")
+end
+
+function lxml.namespace(id) -- or remapped name?
+ local root = get_id(id)
+ texsprint(root.rn or root.ns or "")
+end
+
+function lxml.flush(id)
+ id = get_id(id)
+ local dt = id and id.dt
+ if dt then
+ xmlsprint(dt)
+ end
+end
+
+function lxml.snippet(id,i)
+ local e = get_id(id)
+ if e then
+ local edt = e.dt
+ if edt then
+ xmlsprint(edt[i])
+ end
+ end
+end
+
+function lxml.direct(id)
+ xmlsprint(get_id(id))
+end
+
+function lxml.command(id,pattern,cmd)
+ local i, p = get_id(id,true)
+ local collected = lxmlparseapply(i,pattern)
+ if collected then
+ local rootname = p or i.name
+ for c=1,#collected do
+ local e = collected[c]
+ local ix = e.ix
+ if not ix then
+ addindex(rootname,false,true)
+ ix = e.ix
+ end
+ texsprint(ctxcatcodes,"\\xmlw{",cmd,"}{",rootname,"::",ix,"}")
+ end
+ end
+end
+
+-- loops
+
+function lxml.collected(id,pattern,reverse)
+ return xmlcollected(get_id(id),pattern,reverse)
+end
+
+function lxml.elements(id,pattern,reverse)
+ return xmlelements(get_id(id),pattern,reverse)
+end
+
+-- obscure ones
+
+lxml.info = lxml.name
+
+-- testers
+
+local found, empty = xml.found, xml.empty
+
+local doif, doifnot, doifelse = commands.doif, commands.doifnot, commands.doifelse
+
+function lxml.doif (id,pattern) doif (found(get_id(id),pattern)) end
+function lxml.doifnot (id,pattern) doifnot (found(get_id(id),pattern)) end
+function lxml.doifelse (id,pattern) doifelse(found(get_id(id),pattern)) end
+function lxml.doiftext (id,pattern) doif (not empty(get_id(id),pattern)) end
+function lxml.doifnottext (id,pattern) doifnot (not empty(get_id(id),pattern)) end
+function lxml.doifelsetext (id,pattern) doifelse(not empty(get_id(id),pattern)) end
+
+-- special case: "*" and "" -> self else lpath lookup
+
+--~ function lxml.doifelseempty(id,pattern) doifelse(isempty(get_id(id),pattern ~= "" and pattern ~= nil)) end -- not yet done, pattern
+
+-- status info
+
+statistics.register("xml load time", function()
+ if noffiles > 0 or nofconverted > 0 then
+ return format("%s seconds, %s files, %s converted", statistics.elapsedtime(xml), noffiles, nofconverted)
+ else
+ return nil
+ end
+end)
+
+statistics.register("lxml preparation time", function()
+ if noffiles > 0 or nofconverted > 0 then
+ return format("%s seconds, %s nodes, %s lpath calls, %s cached calls",
+ statistics.elapsedtime(lxml), nofindices, xml.lpathcalls(), xml.lpathcached())
+ else
+ return nil
+ end
+end)
+
+-- misc
+
+function lxml.nonspace(id,pattern) -- slow, todo loop
+ xmltprint(xmlcollect(get_id(id),pattern,true))
+end
+
+function lxml.strip(id,pattern,nolines)
+ xml.strip(get_id(id),pattern,nolines)
+end
+
+function lxml.stripped(id,pattern,nolines)
+ local str = xmlcontent(get_id(id),pattern) or ""
+ str = gsub(str,"^%s*(.-)%s*$","%1")
+ if nolines then
+ str = gsub(str,"%s+"," ")
+ end
+ xmlsprint(str)
+end
diff --git a/tex/context/base/lxml-xml.lua b/tex/context/base/lxml-xml.lua
new file mode 100644
index 000000000..7ff3f5955
--- /dev/null
+++ b/tex/context/base/lxml-xml.lua
@@ -0,0 +1,242 @@
+if not modules then modules = { } end modules ['lxml-xml'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local finalizers = xml.finalizers.xml
+local xmlfilter = xml.filter -- we could inline this one for speed
+local xmltostring = xml.tostring
+local xmlserialize = xml.serialize
+
+local function first(collected)
+ return collected and collected[1]
+end
+
+local function last(collected)
+ return collected and collected[#collected]
+end
+
+local function all(collected)
+ return collected
+end
+
+local function reverse(collected)
+ if collected then
+ local reversed = { }
+ for c=#collected,1,-1 do
+ reversed[#reversed+1] = collected[c]
+ end
+ return reversed
+ end
+end
+
+local function attribute(collected,name)
+ local at = collected and collected[1].at
+ return at and at[name]
+end
+
+local function att(id,name)
+ local at = id.at
+ return at and at[name]
+end
+
+local function count(collected)
+ return (collected and #collected) or 0
+end
+
+local function position(collected,n)
+ if collected then
+ n = tonumber(n) or 0
+ if n < 0 then
+ return collected[#collected + n + 1]
+ else
+ return collected[n]
+ end
+ end
+end
+
+local function index(collected)
+ if collected then
+ return collected[1].ni
+ end
+end
+
+local function attributes(collected,arguments)
+ if collected then
+ local at = collected[1].at
+ if arguments then
+ return at[arguments]
+ elseif next(at) then
+ return at -- all of them
+ end
+ end
+end
+
+local function chainattribute(collected,arguments) -- todo: optional levels
+ if collected then
+ local e = collected[1]
+ while e do
+ local at = e.at
+ if at then
+ local a = at[arguments]
+ if a then
+ return a
+ end
+ else
+ break -- error
+ end
+ e = e.__p__
+ end
+ end
+ return ""
+end
+
+local function text(collected)
+ if collected then
+ return xmltostring(collected[1]) -- only first as we cannot concat function
+ else
+ return ""
+ end
+end
+
+local function texts(collected)
+ if collected then
+ local t = { }
+ for c=1,#collected do
+ local e = collection[c]
+ if e and e.dt then
+ t[#t+1] = e.dt
+ end
+ end
+ return t
+ end
+end
+
+local function tag(collected,n)
+ if collected then
+ local c
+ if n == 0 or not n then
+ c = collected[1]
+ elseif n > 1 then
+ c = collected[n]
+ else
+ c = collected[#collected-n+1]
+ end
+ return c and c.tg
+ end
+end
+
+local function name(collected,n)
+ if collected then
+ local c
+ if n == 0 or not n then
+ c = collected[1]
+ elseif n > 1 then
+ c = collected[n]
+ else
+ c = collected[#collected-n+1]
+ end
+ if c then
+ if c.ns == "" then
+ return c.tg
+ else
+ return c.ns .. ":" .. c.tg
+ end
+ end
+ end
+end
+
+local function tags(collected,nonamespace)
+ if collected then
+ local t = { }
+ for c=1,#collected do
+ local e = collected[c]
+ local ns, tg = e.ns, e.tg
+ if nonamespace or ns == "" then
+ t[#t+1] = tg
+ else
+ t[#t+1] = ns .. ":" .. tg
+ end
+ end
+ return t
+ end
+end
+
+local function empty(collected)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ if e then
+ local edt = e.dt
+ if edt then
+ local n = #edt
+ if (n > 2) or (n > 0 and edt[1] == "") then
+ return false
+ end
+ end
+ end
+ end
+ end
+ return true
+end
+
+finalizers.first = first
+finalizers.last = last
+finalizers.all = all
+finalizers.reverse = reverse
+finalizers.elements = all
+finalizers.default = all
+finalizers.attribute = attribute
+finalizers.att = att
+finalizers.count = count
+finalizers.position = position
+finalizers.index = index
+finalizers.attributes = attributes
+finalizers.chainattribute = chainattribute
+finalizers.text = text
+finalizers.texts = texts
+finalizers.tag = tag
+finalizers.name = name
+finalizers.tags = tags
+finalizers.empty = empty
+
+-- shortcuts -- we could support xmlfilter(id,pattern,first)
+
+function xml.first(id,pattern)
+ return first(xmlfilter(id,pattern))
+end
+
+function xml.last(id,pattern)
+ return last(xmlfilter(id,pattern))
+end
+
+function xml.count(id,pattern)
+ return count(xmlfilter(id,pattern))
+end
+
+function xml.attribute(id,pattern,a,default)
+ return attribute(xmlfilter(id,pattern),a,default)
+end
+
+function xml.text(id,pattern)
+ return text(xmlfilter(id,pattern))
+end
+
+function xml.raw(id,pattern)
+ return xmlserialize(xmlfilter(id,pattern))
+end
+
+function xml.position(id,pattern,n)
+ return position(xmlfilter(id,pattern),n)
+end
+
+function xml.empty(id,pattern)
+ return empty(xmlfilter(id,pattern))
+end
+
+xml.all = xml.filter
+xml.index = xml.position
+xml.found = xml.filter
diff --git a/tex/context/base/math-vfu.lua b/tex/context/base/math-vfu.lua
index 42b7ef05d..e54d68fbe 100644
--- a/tex/context/base/math-vfu.lua
+++ b/tex/context/base/math-vfu.lua
@@ -223,7 +223,7 @@ function fonts.vf.math.alas(main,id,size)
arrow(main,0x2192,0xFE192,0xFF501,false) -- right
end
-local reverse -- index -> unicode
+local unique = 0 -- testcase: \startTEXpage \math{!\text{-}\text{-}\text{-}} \stopTEXpage
function fonts.basecopy(tfmtable)
local t, c, p = { }, { }, { }
@@ -237,10 +237,13 @@ function fonts.basecopy(tfmtable)
p[k] = v
end
t.characters, t.parameters = c, p
+ unique = unique + 1
+ t.fullname = t.fullname .. "-" .. unique
return t
end
local reported = { }
+local reverse -- index -> unicode
function fonts.vf.math.define(specification,set)
if not reverse then
diff --git a/tex/context/base/meta-pdf.lua b/tex/context/base/meta-pdf.lua
index ed3d1ac18..b33d65bd9 100644
--- a/tex/context/base/meta-pdf.lua
+++ b/tex/context/base/meta-pdf.lua
@@ -47,8 +47,8 @@ resetall()
-- todo: collect and flush packed using pdfliteral node injection but we're
-- in no hurry as this kind of conversion does not happen that often in mkiv
-local function pdfcode(str)
- texsprint(ctxcatcodes,"\\pdfliteral{" .. str .. "}")
+local function pdfcode(str) -- could be a node.write instead
+ texsprint(ctxcatcodes,"\\pdfliteral{",str,"}")
end
local function texcode(str)
diff --git a/tex/context/base/mult-sys.tex b/tex/context/base/mult-sys.tex
index c16ebee18..88f7132e4 100644
--- a/tex/context/base/mult-sys.tex
+++ b/tex/context/base/mult-sys.tex
@@ -160,6 +160,10 @@
\definesystemconstant {hascaption}
\definesystemconstant {haslevel}
+\definesystemconstant {mkiv}
+\definesystemconstant {mkii}
+\definesystemconstant {entities}
+
%D A more experienced \TEX\ user will recognize the next four
%D constants. We need these because font-definitions are
%D partially english.
@@ -612,6 +616,7 @@
\definesystemvariable {wr} % WitRuimte
\definesystemvariable {wl} % WordList
\definesystemvariable {xf} % XML File
+\definesystemvariable {xl} % lxml (mkiv)
\definesystemvariable {xm} % xml (mkiv)
\definesystemvariable {xp} % XML Processing
\definesystemvariable {xy} % schaal
diff --git a/tex/context/base/node-bck.lua b/tex/context/base/node-bck.lua
index 24d0a1592..94fbac85f 100644
--- a/tex/context/base/node-bck.lua
+++ b/tex/context/base/node-bck.lua
@@ -6,6 +6,9 @@ if not modules then modules = { } end modules ['node-bck'] = {
license = "see context related readme files"
}
+-- beware, this one takes quite some runtime, so we need a status flag
+-- maybe some page related state
+
local hlist = node.id("hlist")
local vlist = node.id("vlist")
diff --git a/tex/context/base/node-fnt.lua b/tex/context/base/node-fnt.lua
index 3ca6de0bd..72bb140ca 100644
--- a/tex/context/base/node-fnt.lua
+++ b/tex/context/base/node-fnt.lua
@@ -178,7 +178,6 @@ else do
-- X000 1100 = 12 = 0x1C = leftghost
-- X001 0100 = 20 = 0x14 = rightghost
-
function nodes.protect_glyphs(head)
local done = false
for g in traverse_id(glyph,head) do
diff --git a/tex/context/base/node-inj.lua b/tex/context/base/node-inj.lua
index 2a7ea9263..2befb0167 100644
--- a/tex/context/base/node-inj.lua
+++ b/tex/context/base/node-inj.lua
@@ -309,11 +309,12 @@ function nodes.inject_kerns(head,where,keep)
-- if rlmode and rlmode < 0 then
-- n.xoffset = p.xoffset + d[1]
-- else
+local k = wx[p]
+if k then
+ n.xoffset = p.xoffset - d[1] - k[2]
+else
n.xoffset = p.xoffset - d[1]
---~ local k = wx[p]
---~ if k then
---~ wx[n] = k
---~ end
+end
-- end
if mk[p] then
n.yoffset = p.yoffset + d[2]
diff --git a/tex/context/base/node-ref.lua b/tex/context/base/node-ref.lua
index d7ead7163..02f6ca82d 100644
--- a/tex/context/base/node-ref.lua
+++ b/tex/context/base/node-ref.lua
@@ -112,6 +112,9 @@ local function inject_list(id,current,reference,make,stack,pardir,txtdir)
if id == hlist then
-- can be either an explicit hbox or a line and there is no way
-- to recognize this; anyway only if ht/dp (then inline)
+ --
+ -- to be tested: 0=unknown, 1=linebreak, 2=hbox
+--~ if id.subtype == 1 then
local sr = stack[reference]
if first then
if sr and sr[2] then
@@ -133,6 +136,10 @@ local function inject_list(id,current,reference,make,stack,pardir,txtdir)
else
-- also weird
end
+--~ else
+--~ print("!!!!!!!!!!!!!!!!!")
+ -- simple
+--~ end
else
-- ok
end
@@ -185,26 +192,27 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx
txtdir = current.dir
end
elseif id == hlist or id == vlist then
---~ if r and (not skip or r > skip) then
if not reference and r and (not skip or r > skip) then
inject_list(id,current,r,make,stack,pardir,txtdir)
---~ done[r] = true
end
-if r then done[r] = (done[r] or 0) + 1 end
+ if r then
+ done[r] = (done[r] or 0) + 1
+ end
local list = current.list
if list then
local _
current.list, _, pardir, txtdir = inject_areas(list,attribute,make,stack,done,r or skip or 0,current,pardir,txtdir)
end
-if r then done[r] = done[r] - 1 end
+ if r then
+ done[r] = done[r] - 1
+ end
elseif not r then
-- just go on, can be kerns
elseif not reference then
reference, first, last, firstdir = r, current, current, txtdir
elseif r == reference then
last = current
---~ elseif not done[reference] then
-elseif (done[reference] or 0) == 0 then
+ elseif (done[reference] or 0) == 0 then
if not skip or r > skip then
head, current = inject_range(head,first,last,reference,make,stack,parent,pardir,firstdir)
reference, first, last, firstdir = nil, nil, nil, nil
@@ -214,7 +222,6 @@ elseif (done[reference] or 0) == 0 then
end
current = current.next
end
---~ if reference and not done[reference] then
if reference and (done[reference] or 0) == 0 then
head = inject_range(head,first,last,reference,make,stack,parent,pardir,firstdir)
end
diff --git a/tex/context/base/pack-rul.mkiv b/tex/context/base/pack-rul.mkiv
index 807532665..ecf69d3d6 100644
--- a/tex/context/base/pack-rul.mkiv
+++ b/tex/context/base/pack-rul.mkiv
@@ -2892,15 +2892,13 @@
\setbox\scratchbox\hbox to \hsize
{\dimen4\dimexpr .5ex+.5\linewidth\relax
\dimen6\dimexpr-.5ex+.5\linewidth\relax
- \doifnothing{#1}\firstargumentfalse
- \iffirstargument
- \doifelse\@@tllocation\v!inmargin
- {\llap{\doattributes\??tl\c!style\c!color{#1}\hskip\leftmargindistance}}
- {\color[\@@tlrulecolor]
- {\vrule\!!height\dimen4\!!depth\dimen6\!!width\@@tlwidth}%
- \hbox spread 2\dimexpr\@@tldistance\relax
- {\hss\doattributes\??tl\c!style\c!color{\strut#1}\hss}}%
- \fi
+ \doifsomething{#1}
+ {\doifelse\@@tllocation\v!inmargin
+ {\llap{\doattributes\??tl\c!style\c!color{#1}\hskip\leftmargindistance}}
+ {\color[\@@tlrulecolor]
+ {\vrule\!!height\dimen4\!!depth\dimen6\!!width\@@tlwidth}%
+ \hbox spread 2\dimexpr\@@tldistance\relax
+ {\hss\doattributes\??tl\c!style\c!color{\strut#1}\hss}}}%
\color[\@@tlrulecolor]
{\leaders\hrule\!!height\dimen4\!!depth\dimen6\hfill}}%
\ht\scratchbox\strutht
diff --git a/tex/context/base/page-lin.lua b/tex/context/base/page-lin.lua
index 0efb6314e..c8f5161d8 100644
--- a/tex/context/base/page-lin.lua
+++ b/tex/context/base/page-lin.lua
@@ -42,15 +42,16 @@ nodes.lines.scratchbox = nodes.lines.scratchbox or 0
-- cross referencing
function nodes.lines.number(n)
+ n = tonumber(n)
local cr = cross_references[n] or 0
cross_references[n] = nil
return cr
end
-local function resolve(n,m)
+local function resolve(n,m) -- we can now check the 'line' flag (todo)
while n do
local id = n.id
- if id == whatsit then
+ if id == whatsit then -- why whatsit
local a = has_attribute(n,line_reference)
if a then
cross_references[a] = m
@@ -62,6 +63,33 @@ local function resolve(n,m)
end
end
+function nodes.lines.finalize(t)
+ local getnumber = nodes.lines.number
+ for _,p in next, t do
+ for _,r in next, p do
+ if r.metadata.kind == "line" then
+ local e = r.entries
+ e.linenumber = getnumber(e.text or 0)
+ end
+ end
+ end
+end
+
+local filters = jobreferences.filters
+local helpers = structure.helpers
+
+jobreferences.registerfinalizer(nodes.lines.finalize)
+
+filters.line = filters.line or { }
+
+function filters.line.default(data)
+ helpers.title(data.entries.linenumber or "?",data.metadata)
+end
+
+function filters.line.page(data,prefixspec,pagespec) -- redundant
+ helpers.prefixpage(data,prefixspec,pagespec)
+end
+
-- boxed variant
nodes.lines.boxed = { }
diff --git a/tex/context/base/page-lin.mkiv b/tex/context/base/page-lin.mkiv
index c82d4d520..c2dbfb774 100644
--- a/tex/context/base/page-lin.mkiv
+++ b/tex/context/base/page-lin.mkiv
@@ -95,12 +95,17 @@
\def\mkstoptextlinenumbering
{\doresetattribute{line-number}}
+% we could make this a bit more efficient by putting the end reference
+% in the same table as the start one but why make thinsg complex ...
+
+\let\dofinishlinereference\dofinishfullreference
+
\def\mksomelinereference#1#2#3%
{\dontleavehmode\begingroup
\global\advance\linerefcounter\plusone
\dosetattribute{line-reference}\linerefcounter
- % this will change and is troublesome anyway
- #3\textreference[#2]{\noexpand\ctxlua{tex.sprint(nodes.lines.number(\the\linerefcounter))}}%
+ #3%
+ \expanded{\dodosetreference{line}{#2}{}{\the\linerefcounter}}% kind labels userdata text
\endgroup}
\def\mkstartlinereference#1{\mksomelinereference{#1}{lr:b:#1}{}\ignorespaces}
@@ -388,9 +393,9 @@
\def\doifelsesamelinereference#1#2#3%
{\doifreferencefoundelse{lr:b:#1}
- {\let\fline\currenttextreference
+ {\edef\fline{\currentreferencetext}%
\doifreferencefoundelse{lr:e:#1}
- {\let\tline\currenttextreference
+ {\edef\tline{\currentreferencetext}%
\ifx\fline\tline#2\else#3\fi}
{\unknownreference{#1}#2}}
{\unknownreference{#1}#2}}
diff --git a/tex/context/base/scrp-ini.lua b/tex/context/base/scrp-ini.lua
index f0224d311..b28c297d0 100644
--- a/tex/context/base/scrp-ini.lua
+++ b/tex/context/base/scrp-ini.lua
@@ -265,6 +265,8 @@ end
-- eventually we might end up with more extensive parsing
-- todo: pass t[start..stop] == original
+--
+-- one of the time consuming functiions:
function scripts.preprocess(head)
local start = first_character(head)
diff --git a/tex/context/base/sort-lan.mkii b/tex/context/base/sort-lan.mkii
index ad5232b02..26ee80405 100644
--- a/tex/context/base/sort-lan.mkii
+++ b/tex/context/base/sort-lan.mkii
@@ -200,4 +200,18 @@
\exportsortdivision {z+1} {zcaron}
\stopmode
+% Polish:
+
+\startmode[sortorder-pl]
+ \exportsortrule {aogonek} {a+1}
+ \exportsortrule {cacute} {c+1}
+ \exportsortrule {eogonek} {e+1}
+ \exportsortrule {lstroke} {l+1}
+ \exportsortrule {nacute} {n+1}
+ \exportsortrule {oacute} {o+1}
+ \exportsortrule {sacute} {s+1}
+ \exportsortrule {zacute} {z+1}
+ \exportsortrule {zdotaccent} {z+2}
+\stopmode
+
\endinput
diff --git a/tex/context/base/spac-ver.lua b/tex/context/base/spac-ver.lua
index 2ef7afbf9..dbb5b0f39 100644
--- a/tex/context/base/spac-ver.lua
+++ b/tex/context/base/spac-ver.lua
@@ -309,7 +309,7 @@ do -- todo: interface.variables
elseif keyword == k_category then
local category = tonumber(detail)
if category then
- texsprint(ctxcatcodes,format("\\setblankcategory{%s}",category))
+ texsprint(ctxcatcodes,"\\setblankcategory{",category,"}")
if category ~= oldcategory then
texsprint(ctxcatcodes,"\\flushblankhandling")
oldcategory = category
@@ -318,25 +318,20 @@ do -- todo: interface.variables
elseif keyword == k_order and detail then
local order = tonumber(detail)
if order then
- texsprint(ctxcatcodes,format("\\setblankorder{%s}",order))
+ texsprint(ctxcatcodes,"\\setblankorder{",order,"}")
end
elseif keyword == k_penalty and detail then
local penalty = tonumber(detail)
if penalty then
- texsprint(ctxcatcodes,format("\\setblankpenalty{%s}",penalty))
+ texsprint(ctxcatcodes,"\\setblankpenalty{",penalty,"}")
end
else
amount = tonumber(amount) or 1
local sk = skip[keyword]
---~ if sk then
---~ texsprint(ctxcatcodes,format("\\addblankskip{%s}{%s}{%s}",amount,sk[1],sk[2] or sk[1]))
---~ else -- no check
---~ texsprint(ctxcatcodes,format("\\addblankskip{%s}{%s}{%s}",amount,keyword,keyword))
---~ end
if sk then
- texsprint(ctxcatcodes,format("\\addpredefinedblankskip{%s}{%s}",amount,keyword))
+ texsprint(ctxcatcodes,"\\addpredefinedblankskip{",amount,"}{",keyword,"}")
else -- no check
- texsprint(ctxcatcodes,format("\\addaskedblankskip{%s}{%s}",amount,keyword))
+ texsprint(ctxcatcodes,"\\addaskedblankskip{",amount,"}{",keyword,"}")
end
end
end
diff --git a/tex/context/base/spac-ver.mkiv b/tex/context/base/spac-ver.mkiv
index 229a49193..7cf33169b 100644
--- a/tex/context/base/spac-ver.mkiv
+++ b/tex/context/base/spac-ver.mkiv
@@ -1594,6 +1594,8 @@
\unexpanded\def\vspacing
{\dosingleempty\dovspacing}
+% todo: when packed blocks blank, we need to enable forced
+
\def\dovspacing % blank also has a \flushnotes
{\ifinpagebody
\expandafter\dovspacingyes
diff --git a/tex/context/base/strc-ini.lua b/tex/context/base/strc-ini.lua
index a46827902..8fa304ed4 100644
--- a/tex/context/base/strc-ini.lua
+++ b/tex/context/base/strc-ini.lua
@@ -24,7 +24,7 @@ local format, concat, match = string.format, table.concat, string.match
local count, texwrite, texprint, texsprint = tex.count, tex.write, tex.print, tex.sprint
local type, next, tonumber, tostring = type, next, tonumber, tostring
-local ctxcatcodes, xmlcatcodes = tex.ctxcatcodes, 11 -- tex.xmlcatcodes
+local ctxcatcodes, xmlcatcodes = tex.ctxcatcodes, 11 -- tex.xmlcatcodes -- tricky as we're in notcatcodes
local trace_processors = false trackers.register("structure.processors", function(v) trace_processors = v end)
@@ -157,7 +157,7 @@ local tags = {
entry = "ctx:registerentry",
}
-function helpers.title(title,metadata)
+function helpers.title(title,metadata) -- brrr
if title and title ~= "" then
if metadata then
if metadata.coding == "xml" then
diff --git a/tex/context/base/strc-ref.lua b/tex/context/base/strc-ref.lua
index a145098df..7698f203b 100644
--- a/tex/context/base/strc-ref.lua
+++ b/tex/context/base/strc-ref.lua
@@ -40,21 +40,31 @@ local exporters, runners = jobreferences.exporters, jobreferences.runners
local currentreference = nil
-jobreferences.initializers = jobreferences.initializers or { }
+local initializers = { }
+local finalizers = { }
function jobreferences.registerinitializer(func) -- we could use a token register instead
- jobreferences.initializers[#jobreferences.initializers+1] = func
+ initializers[#initializers+1] = func
+end
+function jobreferences.registerfinalizer(func) -- we could use a token register instead
+ finalizers[#finalizers+1] = func
end
local function initializer()
tobesaved, collected = jobreferences.tobesaved, jobreferences.collected
- for k,v in ipairs(jobreferences.initializers) do
- v(tobesaved,collected)
+ for i=1,#initializers do
+ initializers[i](tobesaved,collected)
+ end
+end
+local function finalizer()
+ tobesaved = jobreferences.tobesaved
+ for i=1,#finalizers do
+ finalizers[i](tobesaved)
end
end
if job then
- job.register('jobreferences.collected', jobreferences.tobesaved, initializer)
+ job.register('jobreferences.collected', jobreferences.tobesaved, initializer, finalizer)
end
-- todo: delay split till later as in destinations we split anyway
diff --git a/tex/context/base/strc-sec.mkiv b/tex/context/base/strc-sec.mkiv
index 7510934fd..87e38274b 100644
--- a/tex/context/base/strc-sec.mkiv
+++ b/tex/context/base/strc-sec.mkiv
@@ -369,7 +369,7 @@
\c!saveinlist=\ifconditional\structureheadtolist\v!yes\else\v!no\fi,
\c!level=\currentstructureheadlevel,
\c!name=#1,
- \c!number=\ifconditional\structureheadshownumber\v!yes\else\v!no\fi,
+ \c!number=\ifconditional\structureheaddoincrement\ifconditional\structureheadshownumber\v!yes\else\v!no\fi\else\v!no\fi,
\c!bookmark=,
\c!marking=,
\c!list=,
diff --git a/tex/context/base/supp-fil.mkii b/tex/context/base/supp-fil.mkii
index 1e86498e4..fc0492442 100644
--- a/tex/context/base/supp-fil.mkii
+++ b/tex/context/base/supp-fil.mkii
@@ -392,6 +392,8 @@
\readfile{#1}{#2}{#3}%
\popcatcodetable}
+\ifdefined\xmlcatcodes \else \let\xmlcatcodes\xmlcatcodesn \fi
+
\def\readxmlfile#1#2#3%
{\pushcatcodetable \catcodetable \xmlcatcodes
\readfile{#1}{#2}{#3}%
diff --git a/tex/context/base/syst-aux.mkiv b/tex/context/base/syst-aux.mkiv
index a7c83f246..fe2fbefbe 100644
--- a/tex/context/base/syst-aux.mkiv
+++ b/tex/context/base/syst-aux.mkiv
@@ -3403,7 +3403,7 @@
%D for conditional errors.
%D Krzysztof Leszczynski suggested to provide access to the level by
-%D means of a \type {#1}. I decided to pass the more frquently used
+%D means of a \type {#1}. I decided to pass the more frequently used
%D level as \type {#1} and the less favoured depth as \type {#2}. The
%D intended usage is:
%D
@@ -3431,6 +3431,15 @@
\global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel
\@EA\dodorecurse\@EA1\@EA{\number#1}}
+\long\def\ydorecurse#1#2%
+ {\global\advance\outerrecurse \plusone
+ \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel
+ \let\recurselevel\!!plusone
+ \long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname##1##2{#2}%
+ \expandrecursecontent
+ \@EA\let\@EA\recurselevel\csname\@@irecurse\recursedepth\endcsname
+ \global\advance\outerrecurse \minusone}
+
\long\def\dostepwiserecurse#1#2#3#4% can be made faster by postponing #4
{\global\advance\outerrecurse \plusone
\long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname##1##2{#4}%
diff --git a/tex/context/base/syst-ext.mkii b/tex/context/base/syst-ext.mkii
index 649ab0530..f9827db8b 100644
--- a/tex/context/base/syst-ext.mkii
+++ b/tex/context/base/syst-ext.mkii
@@ -969,7 +969,7 @@
%D for conditional errors.
%D Krzysztof Leszczynski suggested to provide access to the level by
-%D means of a \type {#1}. I decided to pass the more frquently used
+%D means of a \type {#1}. I decided to pass the more frequently used
%D level as \type {#1} and the less favoured depth as \type {#2}. The
%D intended usage is:
%D
@@ -997,6 +997,15 @@
\global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel
\@EA\dodorecurse\@EA1\@EA{\number#1}}
+\long\def\ydorecurse#1#2%
+ {\global\advance\outerrecurse \plusone
+ \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel
+ \let\recurselevel\!!plusone
+ \long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname##1##2{#2}%
+ \expandrecursecontent
+ \@EA\let\@EA\recurselevel\csname\@@irecurse\recursedepth\endcsname
+ \global\advance\outerrecurse \minusone}
+
\long\def\dostepwiserecurse#1#2#3#4% can be made faster by postponing #4
{\global\advance\outerrecurse \plusone
\long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname##1##2{#4}%
diff --git a/tex/context/base/syst-ltx.tex b/tex/context/base/syst-ltx.tex
new file mode 100644
index 000000000..ae89ff25b
--- /dev/null
+++ b/tex/context/base/syst-ltx.tex
@@ -0,0 +1,56 @@
+%D \module
+%D [ file=syst-ltx,
+%D version=2009.10.13,
+%D title=\CONTEXT\ System Macros,
+%D subtitle=General,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D \macros
+%D {newcommand}
+%D
+%D This module replaces \type {t-bibltx} and implements the
+%D \LATEX\ newcommand (sort of). This command is not to be
+%D used directly but only is there for the occasional
+%D \BIBTEX\ file that uses it.
+%D
+%D \starttyping
+%D \newcommand\oeps {oeps}
+%D \newcommand\oeps[6] {oeps[#1]#6}
+%D \newcommand\oeps[6][whatever]{oeps[#1]#6}
+%D \stoptyping
+
+\unprotect
+
+\def\newcommand#1%
+ {\dotripleempty\donewcommand[#1]}
+
+\def\donewcommand
+ {\ifthirdargument
+ \expandafter\donewcommandtwo
+ \else\ifsecondargument
+ \expandafter\expandafter\expandafter\donewcommandone
+ \else
+ \expandafter\expandafter\expandafter\donewcommandzero
+ \fi\fi}
+
+\def\donewcommandzero[#1][#2][#3]%
+ {\long\def#1}
+
+\def\donewcommandone[#1][#2][#3]%
+ {\scratchtoks{\long\def#1}%
+ \dorecurse{#2}{\scratchtoks\expandafter{\the\scratchtoks######1}}%
+ \the\scratchtoks}
+
+\def\donewcommandtwo[#1][#2][#3]%
+ {\long\def#1{\doifnextcharelse[{\getvalue{>>\string#1>>}}{\getvalue{>>\string#1>>}[#3]}}%
+ \scratchtoks{\long\setvalue{>>\string#1>>}[##1]}%
+ \dostepwiserecurse{2}{#2}{1}{\scratchtoks\expandafter{\the\scratchtoks######1}}%
+ \the\scratchtoks}
+
+\protect \endinput
diff --git a/tex/context/base/x-ct.mkiv b/tex/context/base/x-ct.mkiv
index 17ea25408..03a0e4b69 100644
--- a/tex/context/base/x-ct.mkiv
+++ b/tex/context/base/x-ct.mkiv
@@ -45,8 +45,8 @@ do
local function specifiedtemplate(root,templatespec)
local template = { }
- for r, d, k in xml.elements(root,templatespec) do
- local at = d[k].at
+ for e in xml.collected(root,templatespec) do
+ local at = e.at
local tm = halignments[at.align] or ""
if toboolean(at.paragraph) then
tm = tm .. "p"
@@ -54,7 +54,7 @@ do
template[#template+1] = tm
end
if #template > 0 then
- return "|" .. table.join(template,"|") .. "|"
+ return "|" .. table.concat(template,"|") .. "|"
else
return nil
end
@@ -62,8 +62,8 @@ do
local function autotemplate(root,rowspec,cellspec)
local max = 0
- for r, d, k in xml.elements(root,rowspec) do
- local n = xml.count(d[k],cellspec)
+ for e in xml.collected(root,rowspec) do
+ local n = xml.count(e,cellspec)
if n > max then max = n end
end
if max == 2 then
@@ -101,10 +101,10 @@ do
lxml.directives.setup(root,'cdx')
-- todo: head and foot
texsprint(tex.ctxcatcodes, string.format("\\starttabulate[%s]",template))
- for r, d, k in xml.elements(root,bodyrowspec) do
+ for e in xml.collected(root,bodyrowspec) do
texsprint(tex.ctxcatcodes, "\\NC ")
- for r, d, k in xml.elements(d[k],cellspec) do
- texsprint(xml.content(d[k]))
+ for e in xml.collected(e,cellspec) do
+ texsprint(xml.content(e))
texsprint(tex.ctxcatcodes, "\\NC")
end
texsprint(tex.ctxcatcodes, "\\NR")
@@ -141,13 +141,12 @@ do
lxml.directives.setup(root,'cdx')
-- todo: alignments
texsprint(tex.ctxcatcodes, string.format("\\startcombination[%s]",template))
- for r, d, k in xml.elements(root,pairspec) do
- local dk = d[k]
+ for e in xml.collected(root,pairspec) do
texsprint(tex.ctxcatcodes,"{")
- xmlsprint(xml.filter(dk,contentspec) or "")
+ xmlsprint(xml.filter(e,contentspec) or "")
texsprint(tex.ctxcatcodes,"}")
texsprint(tex.ctxcatcodes,"{")
- xmlsprint(xml.filter(dk,captionspec) or "")
+ xmlsprint(xml.filter(e,captionspec) or "")
texsprint(tex.ctxcatcodes,"}")
end
texsprint(tex.ctxcatcodes, "\\stopcombination")
@@ -169,34 +168,3 @@ end
\xmlregisterns{context}{context}
\endinput
-
-% this replaces:
-
-% \startxmlsetups tabulate
-% \starttabulate[||p|]
-% \xmlall{#1}{/body/row}
-% \stoptabulate
-% \stopxmlsetups
-% \startxmlsetups tabulate:row
-% \NC \xmlall{#1}{/cell} \NR
-% \stopxmlsetups
-% \startxmlsetups tabulate:cell
-% \xmlflush{#1} \NC
-% \stopxmlsetups
-
-% \startxmlsetups combination
-% \startcollecting
-% \startcollect
-% \startcombination[\xmlatt{#1}{nx}*\xmlatt{#1}{ny}]
-% \stopcollect
-% \xmlloop {#1} {combiblock} {
-% \startcollect
-% {\xmli{/content}{##1}}
-% {\xmli{/caption}{##1}}
-% \stopcollect
-% }
-% \startcollect
-% \stopcombination
-% \stopcollect
-% \stopcollecting
-% \stopxmlsetups
diff --git a/tex/context/base/x-ldx.tex b/tex/context/base/x-ldx.tex
index 750529649..eb242245c 100644
--- a/tex/context/base/x-ldx.tex
+++ b/tex/context/base/x-ldx.tex
@@ -133,8 +133,6 @@
\def\xmldocument{ldx}
-% \processXMLfileMKIV[ldx]
-
\usemodule[abr-02]
% key -> kw
diff --git a/tex/context/base/x-mathml.lua b/tex/context/base/x-mathml.lua
index 46f7248c6..d1ac4f62d 100644
--- a/tex/context/base/x-mathml.lua
+++ b/tex/context/base/x-mathml.lua
@@ -6,22 +6,17 @@ if not modules then modules = { } end modules ['x-mathml'] = {
license = "see context related readme files"
}
+local type, pairs = type, pairs
local utf = unicode.utf8
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+local format, lower = string.format, string.lower
+local utfchar, utffind, utfgmatch = utf.char, utf.find, utf.gmatch
+local xmlsprint, xmlcprint = xml.sprint, xml.cprint
+local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
-lxml = lxml or { }
lxml.mml = lxml.mml or { }
-local texsprint = tex.sprint
-local format = string.format
-local lower = string.lower
-local utfchar = utf.char
-local utffind = utf.find
-local xmlsprint = xml.sprint
-local xmlcprint = xml.cprint
-
-local ctxcatcodes = tex.ctxcatcodes
-
-local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
+local get_id = lxml.get_id
-- an alternative is to remap to private codes, where we can have
-- different properties .. to be done; this will move and become
@@ -389,30 +384,29 @@ local csymbols = {
},
}
-function xml.functions.remapmmlcsymbol(r,d,k)
- local dk = d[k]
- local at = dk.at
+function xml.functions.remapmmlcsymbol(e)
+ local at = e.at
local cd = at.cd
if cd then
cd = csymbols[cd]
if cd then
- local tx = dk.dt[1]
+ local tx = e.dt[1]
if tx and tx ~= "" then
local tg = cd[tx]
if tg then
at.cd = nil
at.cdbase = nil
- dk.dt = { }
+ e.dt = { }
if type(tg) == "table" then
for k, v in pairs(tg) do
if k == "tag" then
- dk.tg = v
+ e.tg = v
else
at[k] = v
end
end
else
- dk.tg = tg
+ e.tg = tg
end
end
end
@@ -420,34 +414,32 @@ function xml.functions.remapmmlcsymbol(r,d,k)
end
end
-function xml.functions.remapmmlbind(r,d,k)
- d[k].tg = "apply"
+function xml.functions.remapmmlbind(e)
+ e.tg = "apply"
end
-function xml.functions.remapopenmath(r,d,k)
- local dk = d[k]
- local tg = dk.tg
+function xml.functions.remapopenmath(e)
+ local tg = e.tg
if tg == "OMOBJ" then
- dk.tg = "math"
+ e.tg = "math"
elseif tg == "OMA" then
- dk.tg = "apply"
+ e.tg = "apply"
elseif tg == "OMB" then
- dk.tg = "apply"
+ e.tg = "apply"
elseif tg == "OMS" then
- -- xml.functions.remapmmlcsymbol(r,d,k)
- local at = dk.at
- dk.tg = "csymbol"
- dk.dt = { at.name or "unknown" }
+ local at = e.at
+ e.tg = "csymbol"
+ e.dt = { at.name or "unknown" }
at.name = nil
elseif tg == "OMV" then
- local at = dk.at
- dk.tg = "ci"
- dk.dt = { at.name or "unknown" }
+ local at = e.at
+ e.tg = "ci"
+ e.dt = { at.name or "unknown" }
at.name = nil
elseif tg == "OMI" then
- dk.tg = "ci"
+ e.tg = "ci"
end
- dk.rn = "mml"
+ e.rn = "mml"
end
function lxml.mml.checked_operator(str)
@@ -461,8 +453,7 @@ end
function lxml.mml.mn(id,pattern)
-- maybe at some point we need to interpret the number, but
-- currently we assume an upright font
- local str = xml.content(lxml.id(id),pattern) or ""
- -- str = str:gsub("^%s*(.-)%s*$","%1")
+ local str = xml.content(get_id(id),pattern) or ""
str = str:gsub("(%s+)",utfchar(0x205F)) -- medspace e.g.: twenty one (nbsp is not seen)
texsprint(ctxcatcodes,(str:gsub(".",n_replacements)))
end
@@ -472,12 +463,12 @@ function characters.remapentity(chr,slot)
end
function lxml.mml.mo(id,pattern)
- local str = xml.content(lxml.id(id),pattern) or ""
+ local str = xml.content(get_id(id),pattern) or ""
texsprint(ctxcatcodes,(utf.gsub(str,".",o_replacements)))
end
function lxml.mml.mi(id,pattern)
- local str = xml.content(lxml.id(id),pattern) or ""
+ local str = xml.content(get_id(id),pattern) or ""
-- str = str:gsub("^%s*(.-)%s*$","%1")
local rep = i_replacements[str]
if rep then
@@ -499,7 +490,7 @@ end
--~ local rightdelimiters = "[" .. table.keys_as_string(r_replacements) .. "]"
function lxml.mml.mfenced(id,pattern) -- multiple separators
- id = lxml.id(id)
+ id = get_id(id)
local left, right, separators = id.at.open or "(", id.at.close or ")", id.at.separators or ","
local l, r = l_replacements[left], r_replacements[right]
texsprint(ctxcatcodes,"\\enabledelimiter")
@@ -510,30 +501,33 @@ function lxml.mml.mfenced(id,pattern) -- multiple separators
texsprint(ctxcatcodes,left)
end
texsprint(ctxcatcodes,"\\disabledelimiter")
- local n = xml.count(id,pattern)
- if n == 0 then
- -- skip
- elseif n == 1 then
- lxml.all(id,pattern)
- else
- local t = { }
- for s in utf.gmatch(separators,"[^%s]") do
- t[#t+1] = s
- end
- for i=1,n do
- lxml.idx(id,pattern,i) -- kind of slow, some day ...
- if i < n then
- local m = t[i] or t[#t] or ""
- if m == "|" then
- m = "\\enabledelimiter\\middle|\\relax\\disabledelimiter"
- elseif m == doublebar then
- m = "\\enabledelimiter\\middle|\\relax\\disabledelimiter"
- elseif m == "{" then
- m = "\\{"
- elseif m == "}" then
- m = "\\}"
+ local collected = lxml.filter(id,pattern)
+ if collected then
+ local n = #collected
+ if n == 0 then
+ -- skip
+ elseif n == 1 then
+ lxml.all(id,pattern)
+ else
+ local t = { }
+ for s in utfgmatch(separators,"[^%s]") do
+ t[#t+1] = s
+ end
+ for i=1,n do
+ xmlsprint(collected[i]) -- to be checked
+ if i < n then
+ local m = t[i] or t[#t] or ""
+ if m == "|" then
+ m = "\\enabledelimiter\\middle|\\relax\\disabledelimiter"
+ elseif m == doublebar then
+ m = "\\enabledelimiter\\middle|\\relax\\disabledelimiter"
+ elseif m == "{" then
+ m = "\\{"
+ elseif m == "}" then
+ m = "\\}"
+ end
+ texsprint(ctxcatcodes,m)
end
- texsprint(ctxcatcodes,m)
end
end
end
@@ -569,10 +563,7 @@ end
function lxml.mml.mmultiscripts(id)
local done, toggle = false, false
- id = lxml.id(id)
- -- for i=1,#id.dt do local e = id.dt[i] if type(e) == table then ...
- for r, d, k in xml.elements(id,"/*") do
- local e = d[k]
+ for e in lxml.collected(id,"/*") do
local tag = e.tg
if tag == "mprescripts" then
texsprint(ctxcatcodes,"{}")
@@ -582,8 +573,7 @@ function lxml.mml.mmultiscripts(id)
end
end
local done, toggle = false, false
- for r, d, k in xml.elements(id,"/*") do
- local e = d[k]
+ for e in lxml.collected(id,"/*") do
local tag = e.tg
if tag == "mprescripts" then
break
@@ -621,10 +611,10 @@ local frametypes = {
function lxml.mml.mcolumn(root)
root = lxml.id(root)
local matrix, numbers = { }, 0
- local function collect(m,dk)
- local tag = dk.tg
+ local function collect(m,e)
+ local tag = e.tg
if tag == "mi" or tag == "mn" or tag == "mo" or tag == "mtext" then
- local str = xml.content(dk)
+ local str = xml.content(e)
for s in utfcharacters(str) do -- utf.gmatch(str,".") btw, the gmatch was bugged
m[#m+1] = { tag, s }
end
@@ -635,25 +625,24 @@ function lxml.mml.mcolumn(root)
end
end
elseif tag == "mspace" or tag == "mline" then
- local str = dk.at.spacing or ""
+ local str = e.at.spacing or ""
for s in utfcharacters(str) do -- utf.gmatch(str,".") btw, the gmatch was bugged
m[#m+1] = { tag, s }
end
elseif tag == "mline" then
- m[#m+1] = { tag, dk }
+ m[#m+1] = { tag, e }
end
end
- for r, d, k in xml.elements(root,"/*") do
+ for e in lxml.collected(root,"/*") do
local m = { }
matrix[#matrix+1] = m
- local dk = d[k]
- if dk.tg == "mrow" then
+ if e.tg == "mrow" then
-- only one level
- for r, d, k in xml.elements(dk,"/*") do
- collect(m,d[k])
+ for e in lxml.collected(e,"/*") do
+ collect(m,e)
end
else
- collect(m,dk)
+ collect(m,e)
end
end
tex.sprint(ctxcatcodes,"\\halign\\bgroup\\hss$#$&$#$\\cr")
@@ -716,10 +705,8 @@ end
local spacesplitter = lpeg.Ct(lpeg.splitat(" "))
function lxml.mml.mtable(root)
- root = lxml.id(root)
-
-- todo: align, rowspacing, columnspacing, rowlines, columnlines
-
+ root = get_id(root)
local at = root.at
local rowalign = at.rowalign
local columnalign = at.columnalign
@@ -732,23 +719,21 @@ function lxml.mml.mtable(root)
texsprint(ctxcatcodes, format("\\bTABLE[frame=%s,offset=%s]",frametypes[frame or "none"] or "off",framespacing))
--~ context.bTABLE { frame = frametypes[frame or "none"] or "off", offset = framespacing }
- for r, d, k in xml.elements(root,"/(mml:mtr|mml:mlabeledtr)") do
+ for e in lxml.collected(root,"/(mml:mtr|mml:mlabeledtr)") do
texsprint(ctxcatcodes,"\\bTR")
--~ context.bTR()
- local dk = d[k]
- local at = dk.at
+ local at = e.at
local col = 0
local rfr = at.frame or (frames and frames [#frames])
local rra = at.rowalign or (rowaligns and rowaligns [#rowaligns])
local rca = at.columnalign or (columnaligns and columnaligns[#columnaligns])
- local ignorelabel = dk.tg == "mlabeledtr"
- for rr, dd, kk in xml.elements(dk,"/mml:mtd") do
+ local ignorelabel = e.tg == "mlabeledtr"
+ for e in lxml.collected(e,"/mml:mtd") do -- nested we can use xml.collected
col = col + 1
if ignorelabel and col == 1 then
-- get rid of label, should happen at the document level
else
- local dk = dd[kk]
- local at = dk.at
+ local at = e.at
local rowspan, columnspan = at.rowspan or 1, at.columnspan or 1
local cra = rowalignments [at.rowalign or (rowaligns and rowaligns [col]) or rra or "center"] or "lohi"
local cca = columnalignments[at.columnalign or (columnaligns and columnaligns[col]) or rca or "center"] or "middle"
@@ -758,16 +743,16 @@ function lxml.mml.mtable(root)
--~ context.bTD { align = format("{%s,%s}",cra,cca), frame = cfr, nx = columnspan, ny = rowspan }
--~ context.bmath()
--~ context.ignorespaces()
- xmlcprint(dk)
+ xmlcprint(e)
texsprint(ctxcatcodes,"\\removeunwantedspaces$\\eTD") -- $
--~ context.emath()
--~ context.removeunwantedspaces()
--~ context.eTD()
end
end
---~ if dk.tg == "mlabeledtr" then
+--~ if e.tg == "mlabeledtr" then
--~ texsprint(ctxcatcodes,"\\bTD")
---~ xmlcprint(xml.first(dk,"/!mml:mtd"))
+--~ xmlcprint(xml.first(e,"/!mml:mtd"))
--~ texsprint(ctxcatcodes,"\\eTD")
--~ end
texsprint(ctxcatcodes,"\\eTR")
@@ -778,19 +763,21 @@ function lxml.mml.mtable(root)
end
function lxml.mml.csymbol(root)
- root = lxml.id(root)
- local encoding = root.at.encoding or ""
- local hash = url.hashed(lower(root.at.definitionUrl or ""))
+ root = get_id(root)
+ local at = root.at
+ local encoding = at.encoding or ""
+ local hash = url.hashed(lower(at.definitionUrl or ""))
local full = hash.original or ""
local base = hash.path or ""
- local text = string.strip(xml.content(root) or "")
- texsprint(ctxcatcodes,format("\\mmlapplycsymbol{%s}{%s}{%s}{%s}",full,base,encoding,text))
+ local text = string.strip(lxml.content(root))
+--~ texsprint(ctxcatcodes,format("\\mmlapplycsymbol{%s}{%s}{%s}{%s}",full,base,encoding,text))
+ texsprint(ctxcatcodes,"\\mmlapplycsymbol{",full,"}{",base,"}{",encoding,"}{",text,"}")
end
function lxml.mml.menclosepattern(root)
- root = lxml.id(root)
+ root = get_id(root)
local a = root.at.notation
if a and a ~= "" then
- texsprint("mml:enclose:"..a:gsub(" +",",mml:enclose:"))
+ texsprint("mml:enclose:",a:gsub(" +",",mml:enclose:"))
end
end
diff --git a/tex/context/base/x-mathml.mkiv b/tex/context/base/x-mathml.mkiv
index 73958e129..e58dee765 100644
--- a/tex/context/base/x-mathml.mkiv
+++ b/tex/context/base/x-mathml.mkiv
@@ -28,7 +28,7 @@
\xmlfilter {\xmldocument} {omt:*/function(remapopenmath)}
\xmlfilter {\xmldocument} {mml:bind/function(remapmmlbind)}
\xmlfilter {\xmldocument} {mml:csymbol/function(remapmmlcsymbol)}
- \xmlsetsetup{\xmldocument} {mml:*} {*}
+ \xmlsetsetup{\xmldocument} {mml:*} {mml:*}
\xmlsetsetup{\xmldocument} {mml:apply/mml:apply/mml:inverse/../../..} {mml:apply:inverse}
\xmlstrip {\xmldocument} {(mml:mi|mml:mo|mml:mn|mml:mtext|mml:csymbol)}
\stopxmlsetups
@@ -334,7 +334,7 @@
\MMLcreset
\MMLdoL
\mmlfirst{#1}
- \ifnum\xmlnofelements{#1}>\plusone
+ \ifnum\xmlcount{#1}>\plusone
\negthinspace % not enough
\left(\MMLcreset\xmlconcatrange{#1}{/*}{2}{}{\MMLseparator,}\right)
\fi
@@ -354,7 +354,7 @@
\startxmlsetups mml:apply:mml:ci
\xmlfirst{#1}{/mml:ci}
- \ifnum\xmlnofelements{#1}>\plusone
+ \ifnum\xmlcount{#1}>\plusone
\left(\MMLcreset\xmlconcatrange{#1}{/*}{2}{}{\MMLseparator,}\right)
\fi
\stopxmlsetups
@@ -368,7 +368,7 @@
% fn
\startxmlsetups mmc:fn:\utfchar{"00B1} % plusminus ±
- \ifnum\xmlnofelements{#1}>\plustwo
+ \ifnum\xmlcount{#1}>\plustwo
\MMLcreset
\left(\xmlconcat{#1}{/*}{2}{}{\mmlfirst{#1}}\right)
\else
@@ -382,7 +382,7 @@
\startxmlsetups mmc:fn
\begingroup
- \edef\mmlnoffn{\xmlnofelements{#1}}
+ \edef\mmlnoffn{\xmlcount{#1}}
\ifnum\mmlnoffn>\plustwo
\def\MMCfnleft {\left(}
\def\MMCfnright{\right)}
@@ -428,7 +428,7 @@
} {
\MMLcreset
\mmlfirst{#1}
- \ifnum\xmlnofelements{#1}>\plusone
+ \ifnum\xmlcount{#1}>\plusone
\negthinspace
\left(\MMLcreset\xmlconcat{#1}{2}{}{\MMLseparator,}\right)
\fi
@@ -759,7 +759,7 @@
\doif \MMLdeclarestate \v!start {
\mathopnolimits{declare}
\mmlfirst{#1}
- \ifnum\xmlnofelements{#1}>\plusone
+ \ifnum\xmlcount{#1}>\plusone
\thickspace
\mathopnolimits{as}
\thickspace
@@ -1589,7 +1589,7 @@
\startxmlsetups mml:vector
\begingroup
- \ifnum\xmlnofelements{#1}>\plusone
+ \ifnum\xmlcount{#1}>\plusone
\doifelse\MMLvectordirection\v!horizontal {
\left(\xmlconcat{#1}{/*}{\MMLseparator\MMLvectorseparator}\right)
} {
@@ -1846,12 +1846,12 @@
% setups
\startxmlsetups mml:mi % todo: mathvariant mathsize mathcolor mathbackground
- \ctxlua{lxml.mml.mi("#1","*")}
+ \ctxlua{lxml.mml.mi("#1","/*")}
\stopxmlsetups
\startxmlsetups mml:mn % todo: mathvariant mathsize mathcolor mathbackground
\begingroup
- \mr \ctxlua{lxml.mml.mn("#1","*")}% no \hbox, would be ok for . , but spoils rest
+ \mr \ctxlua{lxml.mml.mn("#1","/*")}% no \hbox, would be ok for . , but spoils rest
\endgroup
\stopxmlsetups
@@ -1862,7 +1862,7 @@
\startxmlsetups mml:mo
\doif {\xmlatt{#1}{maxsize}} {1} {\settrue\mmlignoredelimiter}
\doif {\xmlatt{#1}{stretchy}} {false} {\settrue\mmlignoredelimiter}
- \ctxlua{lxml.mml.mo("#1","*")}
+ \ctxlua{lxml.mml.mo("#1","/*")}
\setfalse\mmlignoredelimiter
\stopxmlsetups
@@ -2074,8 +2074,9 @@
\startxmlsetups mml:mrow
\begingroup
- \ifnum\xmlcount{#1}{/mml:mo}=\plustwo
- \xmldoifelse {#1} {/mml:mo[position()==1 or position()==\xmlnofelements{#1}]} {% we need a {}
+ \edef\nofmmlrows{\xmlcount{#1}{/mml:mo}}%
+ \ifnum\nofmmlrows=\plustwo
+ \xmldoifelse {#1} {/mml:mo[position()==1 or position()==\nofmmlrows]} {% we need a {}
\def\MMLleft {\left }
\def\MMLright {\right}
\def\MMLmiddle{\middle}
@@ -2140,12 +2141,12 @@
\startxmlsetups mml:mover
% \mathop {
- \edef\mmlovertoken{\xmlraw{#1}{/mml:*[position()==2]}}
+ \edef\mmlovertoken{\xmlraw{#1}{/mml:*[2]}}
\doifelse{\utfmathclass\mmlovertoken}{accent} {
\edef\mmlovercommand{\utfmathcommand\mmlovertoken}
\mmlexecuteifdefined\mmlovercommand\mathematics{\mmlfirst{#1}}
} {
- \edef\mmlbasetoken{\xmlraw{#1}{/mml:*[position()==1]}}
+ \edef\mmlbasetoken{\xmlraw{#1}{/mml:*[1]}}
\edef\mmlbasecommand{\utfmathfiller\mmlbasetoken}
\edef\mmlovercommand{\utfmathfiller\mmlovertoken}
\vbox {
@@ -2164,12 +2165,12 @@
\startxmlsetups mml:munder
% \mathop {
- \edef\mmlundertoken{\xmlraw{#1}{/mml:*[position()==2]}}
+ \edef\mmlundertoken{\xmlraw{#1}{/mml:*[2]}}
\doifelse{\utfmathclass\mmlundertoken}{accent} {
\edef\mmlundercommand{\utfmathcommand\mmlundertoken}
\mmlexecuteifdefined\mmlundercommand\mathematics{\mmlfirst{#1}}
} {
- \edef\mmlbasetoken {\xmlraw{#1}{/mml:*[position()==1]}}
+ \edef\mmlbasetoken {\xmlraw{#1}{/mml:*[1]}}
\edef\mmlbasecommand {\utfmathfiller\mmlbasetoken}
\edef\mmlundercommand{\utfmathfiller\mmlundertoken}
\vtop {
@@ -2187,7 +2188,7 @@
\stopxmlsetups
\startxmlsetups mml:munderover
- \edef\mmlbasetoken{\xmlraw{#1}{/mml:*[position()==1]}}
+ \edef\mmlbasetoken{\xmlraw{#1}{/mml:*[1]}}
\edef\mmlbasecommand{\utfmathcommand\mmlbasetoken}
\mmlexecuteifdefined\mmlbasecommand{\mathematics{\mmlfirst{#1}}}_{\mmlsecond{#1}}^{\mmlthird{#1}}
\stopxmlsetups
diff --git a/tex/context/base/x-pending.mkiv b/tex/context/base/x-pending.mkiv
index 114b81890..20fe5fb6a 100644
--- a/tex/context/base/x-pending.mkiv
+++ b/tex/context/base/x-pending.mkiv
@@ -17,6 +17,7 @@
%D \MKII\ code, when enabled.
\startluacode
+ dofile(resolvers.find_file("lxml-inf.lua"))
local list = { }
function document.check_pending_xml_element(str)
list[str] = (list[str] and (list[str]+1)) or 1
diff --git a/tex/context/base/x-set-11.mkiv b/tex/context/base/x-set-11.mkiv
index 02d75fc4c..639cac03e 100644
--- a/tex/context/base/x-set-11.mkiv
+++ b/tex/context/base/x-set-11.mkiv
@@ -12,6 +12,11 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+% \startluacode
+% collectgarbage("stop")
+% function collectgarbage() return 0 end
+% \stopluacode
+
% todo: for fun: pure lua interface, but as this style evolved over 15 years
% it's a waste of time
%
@@ -141,7 +146,8 @@
{\doifsomething{#1}
{\doonlyonce{setups:#1}
{\xmlloadonly{setups}{#1}{setups}%
- \xmlcommand{setups}{/interface/command}{xml:setups:register}}}} % qualified path saves > 50% runtime
+% \xmlcommand{setups}{/interface/command}{xml:setups:register}}}} % qualified path saves > 50% runtime
+ \xmlfilter{setups}{/interface/command/command(xml:setups:register)}}}} % qualified path saves > 50% runtime
\newif\ifshortsetup
@@ -170,7 +176,8 @@
\showsetupindeed{#1}}
\def\showsetupindeed#1%
- {\xmlcommand{setups}{/interface/command[@name='#1']}{xml:setups:typeset}}
+% {\xmlcommand{setups}{/interface/command[@name='#1']}{xml:setups:typeset}}
+ {\xmlfilter{setups}{/interface/command[@name='#1']/command(xml:setups:typeset)}}
\def\placesetup {\placelistofsorts[texcommand][\c!criterium=\v!used]}
\def\placeallsetups{\placelistofsorts[texcommand][\c!criterium=\v!all ]}
@@ -206,7 +213,8 @@
} {
\tex{}
}
- \xmlfirst{#1}{/sequence}
+% \xmlfirst{#1}{/sequence}
+ \xmlfilter{#1}{/sequence/first()}
\ignorespaces
\egroup
\xmldoif{#1}{/arguments} {
@@ -214,7 +222,8 @@
\enablemode[setups-pass-one]
\doglobal\newcounter\currentSETUPargument
\ignorespaces
- \xmltext{#1}{/arguments}
+% \xmltext{#1}{/arguments}
+ \xmlfilter{#1}{/arguments/text()}
\egroup
}
\doif {\xmlatt{#1}{type}} {environment} {
@@ -224,7 +233,8 @@
\ttsl
}
\tex{\e!stop}
- \xmlfirst{#1}{/sequence/variable}
+% \xmlfirst{#1}{/sequence/variable}
+ \xmlfilter{#1}{/sequence/variable/first()}
\ignorespaces
\egroup
}
@@ -235,7 +245,8 @@
\doglobal\newcounter\currentSETUPargument
\blank[\v!line]
\switchtobodyfont[small]
- \ignorespaces\xmltext{#1}{/arguments}\endgraf
+% \ignorespaces\xmltext{#1}{/arguments}\endgraf
+ \ignorespaces\xmlfilter{#1}{/arguments/text()}\endgraf
\egroup
}
\getvalue{\e!stop setuptext}
@@ -249,7 +260,8 @@
\startxmlsetups xml:setups:resolve
\ignorespaces
- \xmlfirst{setups}{define[@name='\xmlatt{#1}{name}']}
+% \xmlfirst{setups}{define[@name='\xmlatt{#1}{name}']}
+ \xmlfilter{setups}{/interface/define[@name='\xmlatt{#1}{name}']/first()}
\stopxmlsetups
%D This is the first pass; here we generate the top line.
@@ -320,7 +332,8 @@
} {
\xdef\currentSETUPwidth{0pt}%
\bgroup
- \xmlcommand{#1}{/parameter}{xml:setups:parameter:measure}
+% \xmlcommand{#1}{/parameter}{xml:setups:parameter:measure}
+ \xmlfilter{#1}{/parameter/command(xml:setups:parameter:measure)}
\egroup
\startfirstSETUPcolumn{\showSETUPnumber}%
% \xmldoifelseempty {#1} {} {
diff --git a/tex/context/bib/t-bib.mkii b/tex/context/bib/t-bib.mkii
deleted file mode 100644
index ac3494725..000000000
--- a/tex/context/bib/t-bib.mkii
+++ /dev/null
@@ -1,5 +0,0 @@
-% some code will move here
-
-\unprotect
-
-\protect \endinput
diff --git a/tex/context/bib/t-bib.mkiv b/tex/context/bib/t-bib.mkiv
deleted file mode 100644
index 9a01bc7cd..000000000
--- a/tex/context/bib/t-bib.mkiv
+++ /dev/null
@@ -1,62 +0,0 @@
-%D Note by HH:
-%D
-%D We use a still somewhat experimental extension to the list
-%D mechanism. Eventually the bibtex module will use the bibl loader
-%D and access the data by means of lpath expressions. In that case we
-%D don't need to process the bibliography but still need to track
-%D usage as done here.
-
-\unprotect
-
-\startluacode
-local list = { }
-
-bibtexhacks = {
- reset = function() list = { } end,
- add = function(str) list[#list+1] = str end,
- flush = function() tex.sprint(table.concat(list,",")) end,
-}
-\stopluacode
-
-% HACK WILL GO:
-
-\def\namedlistparameter#1#2{\csname\dolistparameter{\??li#1}#2\endcsname}
-
-% TILL HERE
-
-\let\bibrefprefixcounter\!!plusone
-\def\bibrefprefix {\bibrefprefixcounter:}
-\let\preparebibrefprefix\relax
-\let\preparebibreflist \gobbleoneargument
-\let\bibreflist \empty
-
-\setuplist[pubs][\c!state=\s!start]
-
-\installstructurelistprocessor{pubs:userdata}
- {\ctxlua{bibtexhacks.add(structure.lists.uservalue("\currentlist",\currentlistindex,"bibref"))}}
-
-\def\docitation#1%
- {\expanded{\writedatatolist[pubs][bibref=#1]}}
-
-\def\filllocalpublist
- {\edef\currentlist{pubs}%
- \doif{\listparameter\c!criterium}{cite}{\setuplist[pubs][\c!criterium=\v!here]}%
- \ctxlua{bibtexhacks.reset()}%
- \placestructurelist{pubs}{\listparameter\c!criterium}{\listparameter\c!number}%
- \edef\localpublist{\ctxlua{bibtexhacks.flush()}}}
-
-\def\gotobiblink#1[#2]{\doifreferencefoundelse{\bibrefprefix#2}{\goto{#1}[\bibrefprefix#2]}{\unknownreference{#2}}}
-\def\atbiblink [#1]{\doifreferencefoundelse{\bibrefprefix#1}{\at [\bibrefprefix#1]}{\unknownreference{#1}}}
-\def\inbiblink [#1]{\doifreferencefoundelse{\bibrefprefix#1}{\at [\bibrefprefix#1]}{\unknownreference{#1}}}
-
-\ifdefined\normaldodoplacepublications \else % just in case we load twice
-
- \let\normaldodoplacepublications\dodoplacepublications
-
- \def\dodoplacepublications
- {\normaldodoplacepublications
- \doglobal\increment\bibrefprefixcounter}
-
-\fi
-
-\protect \endinput
diff --git a/tex/context/bib/t-bib.tex b/tex/context/bib/t-bib.tex
deleted file mode 100644
index 11ed1309c..000000000
--- a/tex/context/bib/t-bib.tex
+++ /dev/null
@@ -1,1929 +0,0 @@
-%D \module
-%D [ file=t-bib,
-%D version=2009.08.13,
-%D title=\CONTEXT\ Publication Module,
-%D subtitle=Publications,
-%D author=Taco Hoekwater,
-%D date=\currentdate,
-%D copyright=Public Domain]
-%C
-%C Donated to the public domain.
-
-
-%D The original was developed independantly by Taco Hoekwater while still working for Kluwer
-%D Academic publishers (it still used the dutch interface then). Development continued after
-%D he left Kluwer, and in Januari 2005, the then already internationalized file was merged
-%D with the core distribution by Hans Hagen. The current version is once again by Taco.
-%D
-%D More documentation and additional resources can be found on the contextgarden:
-%D \hyphenatedurl{http://wiki.contextgarden.net//Bibliography}.
-
-%D \subject{DONE (dd/mm/yyyy)}
-%D
-%D \startitemize
-%D \item add author definition (and associated system variable) (26/05/2005)
-%D \item add finalnamesep support for Oxford comma (17/09/2005)
-%D \item add \type{\insert...} for: doi, eprint, howpublished (19/09/2005)
-%D \item allow a defaulted \type{\setupcite} (19/11/2005)
-%D \item renamed citation type 'number' to 'serial' (19/11/2005)
-%D \item better definition of \type{\inverted...author} (19/11/2005)
-%D \item don't reset [numbercommand] in \type {\setuppublication} by default (20/11/2005)
-%D \item don't disable other \type {\setuppublication} keys if alternative is present (20/11/2005)
-%D \item drop \type{\sanitizeaccents} (20/11/2005)
-%D \item added \type{\nocite} and \type{\cite[none]} (21/11/2005)
-%D \item added headtext for it (23/11/2005)
-%D \item make \type{\cite[url]} and \type{\cite[doi]} interactive (23/11/2005)
-%D \item make right-aligned labels in the list work even when autohang=no
-%D \item use 'et al.' instead of 'et.al.'. Pointed out by Peter M�nster (30/12/2005)
-%D \item added headtext for cz (31/12/2005)
-%D \item Keep whitespace after \type{\cite} with single argument (31/12/2005)
-%D \item Fix broken \type{\cite{}} support (31/12/2005)
-%D \item Use \type{\readfile} inside \type{\usepublications} instead of \type{\readsysfile} (12/01/2006)
-%D \item Use \type{\currentbibyear} and \type{\currentbibauthor} instead of \type{\YR} and \type{\AU} (05/02/2006)
-%D \item Fix compressed version of authoryear style (05/02/2006)
-%D \item Rename the clashing data fields \type{\url} and \type{\type} to \type{\biburl} and \type{\bibtype} (05/02/2006)
-%D \item Added two french bibl files from Renaud Aubin (06/02/2006)
-%D \item Five new bib class and eight extra bib fields, for IEEEtran (07/02/2006)
-%D \item French keyword translation, provided by Renaud (08/02/2006)
-%D \item fix underscores in undefined keys (22/02/2006)
-%D \item Destroy interactivity in labels of the publication list (13/03/2006)
-%D \item fix multi-cite list compression (11/4/2006)
-%D \item fix \type{\getcitedata} (11/4/2006)
-%D \item magic for chapter bibs (18-25/4/2006)
-%D \item language setting (25/4/2006)
-%D \item use \type{\hyphenatedurl} for \type{\inserturl} (25/4/2006)
-%D \item Add \type{\docitation} to \type{\nocite}(26/4/2006)
-%D \item patents can have numbers, added to bst files (26/4/2006)
-%D \item \type{\docitation} needs a \type{\iftrialtypesetting} (27/4/2006)
-%D \item \type{\filllocalpublist}'s loop is bound by definedness, not resolvedness (27/4/2006)
-%D \item \type{\setuppublications[monthconversion=]} added (15/5/2006)
-%D \item use \type{\undefinedreference} instead of bare question marks (15/5/2006)
-%D \item add grouping around \type{\placepublications} commands (16/5/2006)
-%D \item fix a bug in \type{\cite{<item>}} (17/5/2006)
-%D \item support \type{\cite[authornum]} (18/5/2006)
-%D \item make \type{\cite} unexpandable (20/6/2006)
-%D \item allow hyperlinks in author\&year combo's
-%D (cite list compression has to be off) (20/6/2006)
-%D \item fix duplicate labels for per-chapter style (20/6/2006)
-%D \item allow \type{\setupcite[interaction=(start|stop)]}
-%D \item fix the item number in the publication list with 'numbering=yes' (22/6/2006)
-%D \item make the default criterium for \type{\placepublications} be \type{previous} (23/6/2006)
-%D \item fix \type{\normalauthor} and \type{\normalshortauthor} spacing (29/6/2006)
-%D \item do not typeset empty arguments to \type{\typesetapublication} (29/6/2006)
-%D \item add \type{symbol=none} to \type{\setuplist} in unnumbered
-%D mode to prevent typesetting of bare numbers (29/6/2006)
-%D \item remove two incorrect spaces from bibl-num.tex (1/7/2006)
-%D \item reset font styles within \type{\cite}, so that font switches
-%D in \type{left} stay in effect (12/7/2006)
-%D \item guard added against loading bbl files multiple times (13/7/2006)
-%D \item fix \type{\cite[num]} with compression is on. (14/7/2006)
-%D \item test \type{\iflocation} before deciding to use the
-%D interactive version of cite (18/7/2006)
-%D \item support \type{\setupcite[authoretallimit=1]} (18/7/2006)
-%D \item support use of \type{\cite} within titles and captions by
-%D saveguarding the list item extraction and reference placement
-%D code (19/7/2006)
-%D \item support \type{\setuppublicationlist[title=\chapter]} (4/8/2006)
-%D \item use the expansion of \type{\headtext{pubs}} (4/8/2006)
-%D \item hook added for repeated authors in publication list
-%D \type{\setuppublicationlist[artauthorcommand=\mythreeargscommand]}
-%D (4/8/2006)
-%D \item make the bracketed arguments of \type{\artauthor}, \type{\author}
-%D and \type{\editor} (bbl commands) optional (4/8/2006)
-%D \item the constants \type{sorttype}, \type{compress} and
-%D \type{autohang} have moved to the core (8/8/2006)
-%D \item bibtex is now registered as a program to be run by texexec (8/8/2006)
-%D \item fix a bug in \type{\setupcite[authoretallimit=1]} (9/8/2006)
-%D \item fix a bug inside citations that prevented lastpubsep from ever being
-%D used due to a volatile \type{\commalistsize} (25/8/2006).
-%D \item added the possibility of \type{\placepublications[option=continue]}
-%D (6/9/2006)
-%D \item Mojca translated Master's Thesis to Masterarbeit (bibl-apa-de.tex)
-%D (12/9/2006)
-%D \item Added \type{\setuppublicationlist[maybeyear=off]} by request from
-%D Thomas Schmitz (15/9/2006)
-%D \item Removed some spurious spaces pointed out by willi egger (19/9/2006)
-%D \item Add configuration of bibtex executable name (4/11/2006)
-%D \item Fix numbering=short and numbering=bib (spotted by Matthias W�chter) (4/11/2006)
-%D \item third attempt to get a correct release (5/11/2006)
-%D \item fix a few missing dots in bibl-num.tex (7/12/2006)
-%D \item Patch for DOI's by Tobias Burnus (17/4/2007)
-%D \item Patch for \type{\insertbiburl} and \type{\insertdoi} for Tobias Burnus (18/4/2007)
-%D \item Added a missing \type{\relax} in \type{\dospecialbibinsert},
-%D that made the space before the {\it et al.} text disappear. (18/4/2007)
-%D \item Attempt to fix percent signs in bbl files. As a side-effect,
-%D this prohibits comments in \tex{startpublication} blocks! (17/4/2008)
-%D \item Patch from Matthias W\"achter that allows arbitrary .bst
-%D files to be used with \tex{setupbibtex} (25/9/2008)
-%D \item Extended for the new multilingual setups for the Oct 2008 current of ConTeXt (23/10/2008)
-%D \item Multilingual setups needed another fix (27/10/2008)
-%D \item Two fixes for bibl-apa by Michael Green (27/10/2008)
-%D \item Catalan translation of 'References' (10/11/2008)
-%D \item 'chapter' -> 'chapitre' in bibl-apa-fr (27/11/2008)
-%D \item Run bibtex via os.execute in mkiv modee (01/12/2008)
-%D \item Small correction in bibl-apa's placement of volume
-%D information in articles (05/01/2009)
-%D \item Handle multi-author (more than two) cases in \type{\cite}
-%D (02/03/2009)
-%D \item Suppress a syntax error in \type{cont-xp} mode. The output is
-%D probably not right, though (02/03/2009)
-%D \item Added a \tex{loadmarkfile} at the end, and two new files
-%D from Hans. The \type{t-bib.mkiv} is needed to make the module
-%D work with the new structure code (17/04/2009)
-%D \item Added a patch to \type{t-bib.mkiv} from Hans to make the
-%D cross referencing between multiple citations an
-%D bibliographies work (27/04/2009)
-%D \item Remove a superfluous \type{\unprotect} in t-bib.mkiv (11/05/2009).
-%D \item Patch of incollection in bibl-ams.tex from Xan (08/06/2009).
-%D \item Patch of unpublished in bibl-ams.tex from Xan (22/07/2009).
-%D \item Modified \type{\bibdogetupsometextprefix} so it works for undefined
-%D language labels, from Hans (13/08/2009).
-%D \stopitemize
-%D
-%D \subject{WISHLIST}
-%D
-%D \startitemize
-%D \item link back from publication list to citation
-%D \item export \type {\citation{<cited item>}}
-%D \item support mlbibtex
-%D \item don't load the whole lot, but filter entries instead
-%D \stopitemize
-
-\unprotect
-
-%D start with a temp hack the file will still work with pre-Oct 2008
-%D versions of ConTeXt:
-
-
-\def\startinterface #1
- {\doifnot{#1}{all}{\doifnotinset\currentinterface{#1}{\gobbleuntil\stopinterface}}}
-
-\let\checksetvalue\gobbletwoarguments
-
-
-%\defineinterfacevariable {title} {title}
-%\defineinterfacevariable {short} {short}
-%\defineinterfacevariable {cite} {cite}
-%\defineinterfacevariable {bbl} {bbl}
-%\defineinterfacevariable {bib} {bib}
-%\defineinterfacevariable {author} {author}
-
-%D A few new shortcuts:
-
-\definesystemvariable {pv} % PublicationVariable
-\definesystemvariable {pb} % PuBlication
-
-\definemessageconstant {bib}
-\definefileconstant {bibextension} {bbl}
-
-%D Some user information messages.
-
-\startmessages all library: bib
- title: publications
- 1: file -- not found, unknown style ignored
- 2: file -- not found, waiting for bibtex
- 3: wrote a new auxiliary file \jobname.aux
- 4: loading database from --
- 5: warning: cite argument -- on \the\inputlineno
- 6: loading formatting style from --
-\stopmessages
-
-%D Some constants for the multi-lingual interface
-
-\startinterface all
- \setinterfaceconstant {database} {database}
- \setinterfaceconstant {artauthor} {artauthor}
- \setinterfaceconstant {editor} {editor}
- \setinterfaceconstant {authoretallimit} {authoretallimit}
- \setinterfaceconstant {artauthoretallimit} {artauthoretallimit}
- \setinterfaceconstant {editoretallimit} {editoretallimit}
- \setinterfaceconstant {authoretaldisplay} {authoretaldisplay}
- \setinterfaceconstant {artauthoretaldisplay} {artauthoretaldisplay}
- \setinterfaceconstant {editoretaldisplay} {editoretaldisplay}
- \setinterfaceconstant {authoretaltext} {authoretaltext}
- \setinterfaceconstant {artauthoretaltext} {artauthoretaltext}
- \setinterfaceconstant {editoretaltext} {editoretaltext}
- \setinterfaceconstant {otherstext} {otherstext}
- \setinterfaceconstant {andtext} {andtext}
- \setinterfaceconstant {totalnumber} {totalnumber}
- \setinterfaceconstant {firstnamesep} {firstnamesep}
- \setinterfaceconstant {vonsep} {vonsep}
- \setinterfaceconstant {juniorsep} {juniorsep}
- \setinterfaceconstant {surnamesep} {surnamesep}
- \setinterfaceconstant {lastnamesep} {lastnamesep}
- \setinterfaceconstant {finalnamesep} {finalnamesep}
- \setinterfaceconstant {namesep} {namesep}
- \setinterfaceconstant {pubsep} {pubsep}
- \setinterfaceconstant {lastpubsep} {lastpubsep}
- \setinterfaceconstant {refcommand} {refcommand}
- \setinterfaceconstant {samplesize} {samplesize}
-\stopinterface
-
-\startinterface dutch
- \setinterfacevariable {title} {titel}
- \setinterfacevariable {short} {kort}
- \setinterfacevariable {cite} {cite}
- \setinterfacevariable {bbl} {bbl}
- \setinterfacevariable {bib} {bib}
- \setinterfacevariable {author} {auteur}
-\stopinterface
-
-\startinterface english
- \setinterfacevariable {title} {title}
- \setinterfacevariable {short} {short}
- \setinterfacevariable {cite} {cite}
- \setinterfacevariable {bbl} {bbl}
- \setinterfacevariable {bib} {bib}
- \setinterfacevariable {author} {author}
-\stopinterface
-
-\startinterface german
- \setinterfacevariable {title} {titel}
- \setinterfacevariable {short} {kurz}
- \setinterfacevariable {cite} {cite}
- \setinterfacevariable {bbl} {bbl}
- \setinterfacevariable {bib} {bib}
- \setinterfacevariable {author} {autor}
-\stopinterface
-
-\startinterface czech
- \setinterfacevariable {title} {titul}
- \setinterfacevariable {short} {short}
- \setinterfacevariable {cite} {cite}
- \setinterfacevariable {bbl} {bbl}
- \setinterfacevariable {bib} {bib}
- \setinterfacevariable {author} {autor}
-\stopinterface
-
-\startinterface italian
- \setinterfacevariable {title} {titolo}
- \setinterfacevariable {short} {short}
- \setinterfacevariable {cite} {cite}
- \setinterfacevariable {bbl} {bbl}
- \setinterfacevariable {bib} {bib}
- \setinterfacevariable {author} {autore}
-\stopinterface
-
-\startinterface romanian
- \setinterfacevariable {title} {titlu}
- \setinterfacevariable {short} {short}
- \setinterfacevariable {cite} {cite}
- \setinterfacevariable {bbl} {bbl}
- \setinterfacevariable {bib} {bib}
- \setinterfacevariable {author} {autor}
-\stopinterface
-
-\startinterface french
- \setinterfacevariable {title} {titre}
- \setinterfacevariable {short} {short}
- \setinterfacevariable {cite} {cite}
- \setinterfacevariable {bbl} {bbl}
- \setinterfacevariable {bib} {bib}
- \setinterfacevariable {author} {auteur}
-\stopinterface
-
-\def\biblistname{pubs} % for compatibility
-
-%D how to load the references. There is some new stuff here
-%D to support Idris' (incorrect :-)) use of projects
-
-\let\preloadbiblist\relax
-
-\ifx\currentcomponent\v!text
- % single file
- \edef\temp{\the\everystarttext}%
- \ifx\temp\empty
- % post-starttext
- \def\preloadbiblist{\dousepublications\jobname }%
- \else
- % pre-starttext
- \appendtoks \dousepublications\jobname \to \everystarttext
- \fi
- %
-\else \ifx\currentcomponent\v!project
- % a project file, have to set up the partial products!
- \def\startproduct #1 %
- {\doateverystarttext
- \dousepublications{#1}%
- \donextlevel\v!product\currentproduct
- \doexecutefileonce\doexecutefileonce
- \donotexecutefile\doexecutefile#1\\}%
- %
-\else \ifx\currentcomponent\v!product
- % a product file
- \def\preloadbiblist{\dousepublications\jobname }%
- %
-\else
- % a component? not sure what to do
- \def\preloadbiblist{\dousepublications\jobname }%
- %
-\fi \fi \fi
-
-\definelist[pubs]
-\setuplist[pubs][\c!width=]
-
-
-%D The text string for the publication list header
-
-\setupheadtext[en][pubs=References]
-\setupheadtext[nl][pubs=Literatuur]
-\setupheadtext[de][pubs=Literatur]
-\setupheadtext[it][pubs=Bibliografia]
-\setupheadtext[sl][pubs=Literatura]
-\setupheadtext[fr][pubs=Bibliographie]
-\setupheadtext[ca][pubs=Referències]
-
-%D \macros{bibdoif,bibdoifnot,bibdoifelse}
-%D
-%D Here are a few small helpers that are used a lot
-%D in all the typesetting commands
-%D (\type{\insert...}) we will encounter later.
-
-\long\def\bibdoifelse#1%
- {\@EA\def\@EA\!!stringa\@EA{#1}%
- \ifx\!!stringa\empty
- \expandafter\secondoftwoarguments
- \else
- \expandafter\firstoftwoarguments
- \fi}
-
-\long\def\bibdoifnot#1%
- {\@EA\def\@EA\!!stringa\@EA{#1}%
- \ifx\!!stringa\empty
- \expandafter\firstofoneargument
- \else
- \expandafter\gobbleoneargument
- \fi}
-
-\long\def\bibdoif#1%
- {\@EA\def\@EA\!!stringa\@EA{#1}%
- \ifx\!!stringa\empty
- \expandafter\gobbleoneargument
- \else
- \expandafter\firstofoneargument
- \fi}
-
-
-%D Bibtex settings separated out
-
-%D No point in writing the aux file if there is no database...
-
-\def\setupbibtex{\dosingleempty\dosetupbibtex}
-
-\def\dosetupbibtex[#1]%
- {\let\@@pbdatabase\empty
- \getparameters[\??pb][sort=\s!default,#1]%
- \expanded{\processaction[\@@pbsort]}
- [ \v!no=>\def\bibstyle{cont-no},
- \v!author=>\def\bibstyle{cont-au},
- \v!title=>\def\bibstyle{cont-ti},
- \v!short=>\def\bibstyle{cont-ab},
- \s!default=>\def\bibstyle{cont-no},
- \s!unknown=>\def\bibstyle{\@@pbsort}]%
- \ifx\@@pbdatabase\empty\else \writeauxfile \fi}
-
-\dosetupbibtex[bibtex=bibtex]
-
-%D \macros{writeauxfile}
-%D
-%D Unfortunately, \BIBTEX\ is not the best configurable program
-%D around. The names of the commands it parses as well as the \type{.aux}
-%D extension to the file name are both hardwired.
-%D
-%D This means \CONTEXT\ has to write a \LATEX-style auxiliary file, yuk!
-%D The good news is that it can be rather short. We'll just ask
-%D \BIBTEX\ to output the entire database(s) into the \type{bbl} file.
-%D
-%D The \type{\bibstyle} command controls how the \type{bbl} file will
-%D be sorted. The possibilities are:
-%D
-%D \startitemize[packed]
-%D \item by author (+year, title): cont-au.bst
-%D \item by title (+author, year): cont-ti.bst
-%D \item by short key as in abbrev.bst: cont-ab.bst
-%D \item not sorted at all: cont-no.bst
-%D \stopitemize
-
-\def\writeauxfile
- {\doifmode{*first}
- {\openout \scratchwrite \jobname.aux
- \write \scratchwrite {\string\citation{*}}%
- \write \scratchwrite {\string\bibstyle{\bibstyle}}%
- \write \scratchwrite {\string\bibdata{\@@pbdatabase}}%
- \closeout\scratchwrite
- \showmessage\m!bib{3}{}%
- \doifmodeelse{*mkiv}
- {\ctxlua{os.execute('\@@pbbibtex\space\jobname')}}
- {\expanded{\installprogram{\@@pbbibtex\space\jobname}}}}}
-
-%D \macros{ifsortbycite,iftypesetall,ifautohang,ifbibcitecompress}
-%D
-%D The module needs some new \type{\if} statements.
-
-%D Default sort order of the reference list is by citation.
-
-\newif\ifsortbycite \sortbycitetrue
-
-%D By default, only referenced publications are typeset
-
-\newif\iftypesetall \typesetallfalse
-
-%D Hanging indentation of the publication list
-%D will not adjust itself according to the width of the label.
-
-\newif\ifautohang \autohangfalse
-
-%D Cite lists are compressed, if possible.
-
-\newif\ifbibcitecompress \bibcitecompresstrue
-
-\def\setuppublications
- {\dosingleargument\dosetuppublications}
-
-\def\bibleftnumber#1%
- {#1\hfill~}
-
-
-\def\dosetuppublications[#1]%
- {\getparameters
- [\??pb]
- [\c!alternative=,#1]%
- \doifsomething\@@pbalternative
- {\readsysfile
- {bibl-\@@pbalternative.tex}
- {\showmessage\m!bib{6}{bibl-\@@pbalternative}\let\@@pbalternative\empty}
- {\showmessage\m!bib{1}{bibl-\@@pbalternative}\let\@@pbalternative\empty}}%
- \getparameters
- [\??pb]
- [#1]%
- \processaction
- [\@@pbcriterium]
- [ \v!all=>\typesetalltrue,
- \s!unknown=>\typesetallfalse]%
- \processaction
- [\@@pbautohang]
- [ \v!yes=>\autohangtrue,
- \s!unknown=>\autohangfalse]%
- \processaction
- [\@@pbsorttype]
- [ \v!cite=>\sortbycitetrue,
- \v!bbl=>\sortbycitefalse,
- \s!default=>\sortbycitetrue,
- \s!unknown=>\sortbycitefalse]%
- \processaction
- [\@@pbnumbering]
- [ \v!yes=>\let\@@pbinumbercommand\firstofoneargument,
- \v!no=>\let\@@pbinumbercommand\gobbleoneargument,
- \v!short=>\def\@@pbinumbercommand##1{\getvalue{pbds-\@@pbk}},
- \v!bib=>\def\@@pbinumbercommand##1{\getvalue{pbdn-\@@pbk}},
- \s!unknown=>\let\@@pbinumbercommand\firstofoneargument]%
- \processaction
- [\@@pbrefcommand]
- [\s!default=>\edef\@@citedefault{\@@pbrefcommand},
- \s!unknown=>\edef\@@citedefault{\@@pbrefcommand}]}
-
-% initialize
-
-\def\@@pbrefcommand{num}
-\def\@@pbnumbercommand{\bibleftnumber}
-
-%D \macros{usepublications}
-%D
-%D We need \type{\usereferences} so that it is possible to
-%D refer to page and/or appearance number for publications
-%D in the other document.
-
-\def\usepublications[#1]%
- {\usereferences[#1]\processcommalist[#1]\dousepublications}
-
-\def\dousepublications#1%
- {\doonlyonce
- {#1.\f!bibextension}
- {\readfile{#1.\f!bibextension}
- {\showmessage\m!bib{4}{#1.\f!bibextension}}
- {\showmessage\m!bib{2}{#1.\f!bibextension}}}}
-
-%D \macros{setuppublicationlist}
-%D
-%D This will be the first command in (\BIBTEX-generated) \type{bbl}
-%D files. `samplesize' is a sample value (in case of \BIBTEX-generated
-%D files, this will be the longest `short' key). `totalnumber'
-%D is the total number of entries that will follow in this
-%D file.
-
-%D Both values are only needed for the label calculation
-%D if `autohang' is `true', so by default the command is
-%D not even needed, and therefore I saw no need to give
-%D it it's own system variable and it just re-uses \type{pb}.
-
-\def\setuppublicationlist
- {\dosingleempty\dosetuppublicationlist}
-
-\def\dosetuppublicationlist[#1]%
- {\getparameters[\??pv data][#1]%
- \setuplist
- [pubs]
- [\c!samplesize={AA99},\c!totalnumber={99},
- \c!alternative=a,\c!interaction=,\c!pagenumber=\v!no,#1]}
-
-\def\setuppublicationlayout[#1]#2%
- {\setvalue{\??pv data#1}{#2\unskip}}
-
-%D \macros{bibalternative}
-%D
-%D A nice little shorthand that will be used so we don't have to
-%D key in the weird \type{\@@pv} parameter names all the time.
-
-\def\bibalternative#1%
- {\getvalue{\??pv\@@currentalternative#1}}
-
-%D \macros{simplebibdef,bibcommandlist}
-%D
-%D \type{\simplebibdef} defines \type{bib@#1}, which in turn will
-%D use one argument that is stored in \type{@@pb@#1}.
-%D
-%D \type{\simplebibdef} also defines \type{insert#1}, which can be
-%D used in the argument of \type{\setuppublicationlayout} to fetch
-%D one of the \type{@@pb@} data entries. \type{insert#1} then has
-%D three arguments: \type{#1} are commands to be executed before the
-%D data, \type{#2} are commands to be executed after the data, and
-%D \type{#3} are commands to be executed if the data is not found.
-
-%D \type{\bibcommandlist} is the list of commands that is affected
-%D by this approach. Later on, it will be used to do a series
-%D of assignments from \type{#1} to \type{bib@#1}: e.g
-%D \type{\title} becomes \type{\bib@title} when used within
-%D a publication.
-
-\def\simplebibdef#1% hh: funny expansion ?
- {\@EA\long\@EA\def\csname bib@#1\endcsname##1%
- {\setvalue{\??pb @#1}{##1}%
- \ignorespaces}%
- \@EA\def\csname insert#1\endcsname##1##2##3%
- {\@EA\bibdoifelse
- \@EA{\csname @@pb@#1\endcsname}%
- {##1\csname @@pb@#1\endcsname##2}%
- {##3}%
- }}
-
-\def\bibcommandlist
- {abstract, annotate, arttitle, assignee, bibnumber, bibtype, biburl, chapter, city,
- comment, country, day, dayfiled, doi, edition, eprint, howpublished, isbn, issn,
- issue, journal, keyword, keywords, lastchecked, month, monthfiled, names, nationality,
- note, notes, organization, pages, pubname, pubyear, revision, series, size, thekey,
- title, volume, yearfiled}
-
-
-\processcommacommand[\bibcommandlist]\simplebibdef
-
-\def\insertdoi#1#2#3%
- {{\bibdoifelse{\@@pb@doi}%
- {\edef\ascii{\@EA\detokenize\@EA{\@@pb@doi}}%
- #1\expanded{\gotoDOI{\@@pb@thekey}{\ascii}}#2}{#3}}}
-
-\def\insertbiburl#1#2#3%
- {{\bibdoifelse{\@@pb@biburl}%
- {\edef\ascii{\@EA\detokenize\@EA{\@@pb@biburl}}%
- #1\expanded{\gotoURL{\@@pb@thekey}{\ascii}}#2}{#3}}}
-
-\def\insertmonth#1#2#3%
- {\bibdoifelse{\@@pb@month}%
- {#1\doifnumberelse{\@@pb@month}%
- {\doifconversiondefinedelse\@@pbmonthconversion
- {\convertnumber\@@pbmonthconversion{\@@pb@month}}{\@@pb@month}}%
- {\@@pb@month}#2}{#3}}
-
-\let\inserturl \insertbiburl % for backward compat.
-\let\inserttype\insertbibtype % for backward compat.
-
-\def\newbibfield[#1]%
- {\simplebibdef{#1}%
- \edef\bibcommandlist{\bibcommandlist,#1}}
-
-%D \macros{bib@crossref}
-%D
-%D \type{\crossref} is used in database files to point to another
-%D entry. Because of this special situation, it has to be defined
-%D separately. Since this command will not be seen until at
-%D \type{\placepublications}, it may force extra runs. The same is
-%D true for \type{\cite} commands inside of publications.
-
-\def\bib@crossref#1%
- {\setvalue{\??pb @crossref}{#1}\ignorespaces}
-
-\def\insertcrossref#1#2#3%
- {\bibdoifelse{\@@pb@crossref}
- {#1\@EA\cite\@EA[\@@pb@crossref]#2}
- {#3}}
-
-%D \macros{complexbibdef,specialbibinsert}
-%D
-%D The commands \type{\artauthor}, \type{\author} and
-%D \type{\editor} are more complex than the other commands.
-%D Their argument lists have this form:
-%D
-%D \type{\author[junior]{firstnames}[inits]{von}{surname}}
-%D
-%D (bracketed stuff is optional)
-%D
-%D And not only that, but there also might be more than one of each of
-%D these commands. This is why a special command is needed to insert
-%D them, as well as one extra counter for each command.
-
-%D All of these \type{\@EA}'s and \type{\csnames} make this code
-%D look far more complex than it really is. For example, the argument
-%D \type{author} defines the macro \type{\bib@author} to do two
-%D things: increment the counter \type{\author@num} (let's say to 2)
-%D and next store it's arguments in the macro \type{\@@pb@author2}.
-%D And it defines \type{\insertauthors} to expand into
-%D \starttyping
-%D \specialbibinsert{author}{\author@num}{<before>}{<after>}{<not>}
-%D \stoptyping
-
-\def\docomplexbibdef#1%
- {\def\currentype{#1}%
- \dosingleempty\dodocomplexbibdef}
-
-\def\dodocomplexbibdef[#1]#2%
- {\def\firstarg{#1}\def\secondarg{#2}%
- \dosingleempty\dododocomplexbibdef}
-
-\def\dododocomplexbibdef[#1]#2#3%
- {\@EA\increment\csname \currentype @num\endcsname
- \setevalue{\??pb @\currentype\csname \currentype @num\endcsname}%
- {{\secondarg}{#2}{#3}{#1}{\firstarg}}\ignorespaces}%
-
-\def\complexbibdef#1%
- {\@EA\newcounter\csname #1@num\endcsname
- \@EA\def\csname bib@#1\endcsname{\docomplexbibdef{#1}}%
- \@EA\def\csname insert#1s\endcsname##1##2##3%
- {\specialbibinsert{#1}{\csname #1@num\endcsname}{##1}{\unskip ##2}{##3}}}
-
-\processcommalist[author,artauthor,editor]\complexbibdef
-
-%D Another level of indirection is needed to control the
-%D typesetting of all of these arguments.
-
-%D Btw, there is a conflict between `author' and the predefined interface
-%D variable `auteur'. The old version is overruled `auteur' is
-%D overruled by the systemconstant definition at the top of this file!
-
-
-\newcount\etallimitcounter
-\newcount\etaldisplaycounter
-\newcount\todocounter
-
-\def\specialbibinsert#1#2#3#4#5%
- {\bgroup
- \ifnum#2>\zerocount
- \etallimitcounter =0\bibalternative{#1etallimit}\relax
- \etaldisplaycounter=0\bibalternative{#1etaldisplay}\relax
- \ifnum #2>\etallimitcounter
- \todocounter\etaldisplaycounter
- % just in case ...
- \ifnum\todocounter>\etallimitcounter
- \todocounter\etallimitcounter
- \fi
- \else
- \todocounter#2\relax
- \fi
- \ifnum\todocounter>\zerocount
- % find the current author list
- \let\templist\empty
- \dorecurse{#2}
- {\toks0=\@EA\@EA\@EA{\csname @@pb@#1\recurselevel\endcsname}%
- \ifx\templist\empty \edef\templist{\the\toks0}%
- \else \edef\templist{\templist,\the\toks0}\fi }%
- \doifdefinedelse
- {\??pv data#1\c!command}
- {\doifemptyelsevalue
- {\??pv data#1\c!command}
- {#3\dospecialbibinsert{#1}{\todocounter}{\templist}#4}%
- {#3\getvalue{\??pv data#1\c!command}{#1}{\todocounter}{\templist}#4}}%
- {#3\dospecialbibinsert{#1}{\todocounter}{\templist}#4}%
- \else
- #5%
- \fi
- \else
- #5%
- \fi
- \egroup}
-
-%D This macro does the hard work of inserting a list of people in the
-%D output, with proper regard of all the inbetween strings that can
-%D arise depending on length of the list of people.
-
-%D \#1 = type
-%D \#2 = number of items to be typeset
-%D \#3 = commacommand containing authors
-
-\def\dospecialbibinsert#1#2#3%
- {\getcommacommandsize[#3]%
- \scratchcounter 0
- \def\processauthoritem##1%
- {\advance\scratchcounter1
- \ifnum \numexpr\scratchcounter-1\relax<#2\relax
- \getvalue{\??pv data#1}##1%
- \ifnum \scratchcounter=#2\relax
- \ifnum\etallimitcounter<\commalistsize\relax \bibalternative{#1etaltext}\fi
- \else \ifnum\numexpr\scratchcounter+1 = #2\relax
- \ifnum \commalistsize > \plustwo \bibalternative\c!finalnamesep
- \else \bibalternative\c!lastnamesep \fi
- \else
- \bibalternative\c!namesep
- \fi \fi
- \fi}%
- \processcommacommand[#3]\processauthoritem }
-
-
-%D \macros{invertedauthor,normalauthor,invertedshortauthor,normalshortauthor}
-%D
-%D Just some commands that can be used in \type{\setuppublicationparameters}
-%D If you want to write an extension to the styles, you might
-%D as well define some of these commands yourself.
-%D
-%D The argument liust has been reordered here, and the meanings
-%D are:
-%D
-%D {\obeylines\parskip0pt
-%D \type{#1} firstnames
-%D \type{#2} von
-%D \type{#3} surname
-%D \type{#4} inits
-%D \type{#5} junior
-%D }
-%D
-
-\def\normalauthor#1#2#3#4#5%
- {\bibdoif{#1}{#1\bibalternative\c!firstnamesep}%
- \bibdoif{#2}{#2\bibalternative\c!vonsep}%
- #3%
- \bibdoif{#5}{\bibalternative\c!surnamesep#5\unskip}}
-
-\def\normalshortauthor#1#2#3#4#5%
- {\bibdoif{#4}{#4\bibalternative\c!firstnamesep}%
- \bibdoif{#2}{#2\bibalternative\c!vonsep}%
- #3%
- \bibdoif{#5}{\bibalternative\c!surnamesep#5\unskip}}
-
-\def\invertedauthor#1#2#3#4#5%
- {\bibdoif{#2}{#2\bibalternative\c!vonsep}%
- #3%
- \bibdoif{#5}{\bibalternative\c!juniorsep #5}%
- \bibdoif{#1}{\bibalternative\c!surnamesep #1\unskip}}
-
-\def\invertedshortauthor#1#2#3#4#5%
- {\bibdoif{#2}{#2\bibalternative\c!vonsep}%
- #3%
- \bibdoif{#5}{\bibalternative\c!juniorsep #5}%
- \bibdoif{#4}{\bibalternative\c!surnamesep #4\unskip}}
-
-%D \macros{clearbibitem,clearbibitemtwo,bibitemdefs}
-%D
-%D These are used in \type{\typesetapublication} to do
-%D initializations and cleanups.
-
-\def\clearbibitem#1{\setvalue{\??pb @#1}{}}%
-
-\def\clearbibitemtwo#1%
- {\letvalue{#1@num}\!!zerocount
- \scratchcounter\plusone
- \doloop
- {\doifdefinedelse{\??pb @#1\the\scratchcounter}
- {\letvalue{\??pb @#1\the\scratchcounter}\empty
- \advance\scratchcounter\plusone}%
- {\exitloop}}}
-
-\def\bibitemdefs#1%
- {\@EA\let\@EA\tempa \csname bib@#1\endcsname
- \@EA\let\csname #1\endcsname \tempa }
-
-%D \macros{startpublication}
-%D
-%D We are coming to the end of this module, to the macros that
-%D do typesetting and read the \type{bbl} file.
-
-\newcounter\bibcounter
-
-%D Just a \type{\dosingleempty} is the most friendly
-%D of doing this: there need not even be an argument
-%D to \type{\startpublication}. Of course, then there
-%D is no key either, and it had better be an
-%D article (otherwise the layout will be all screwed up).
-%D
-%D Now prohibits comments, so % can be used for urls
-
-\def\startpublication
- {\edef\bibmodsavedpercent{\the\catcode`\%}%
- \catcode`\%=12
- \dosingleempty\dostartpublication}
-
-\def\stoppublication
- {} % the \catcode of % is reset below
-
-%D Only specifying the key in the argument is also
-%D legal. In storing this stuff into macros, some trickery with
-%D token registers is needed to fix the expansion problems. Even so,
-%D this appears to not always be 100\% safe, so people are
-%D urgently advised to use \ETEX\ instead of traditional \TEX.
-%D
-%D In \ETEX, all expansion problems are conviniently solved by
-%D the primitive \type{\protected}. To put that another way:
-%D
-%D It's not a bug in this module if it does not appear in \ETEX!
-
-\long\def\dostartpublication[#1]#2\stoppublication%
- {\increment\bibcounter
- \bgroup
- \doifassignmentelse{#1}%
- {\getparameters[\??pb][k=,t=article,n=,s=,a=,y=,o=,u=,#1]}%
- {\getparameters[\??pb][k=#1,t=article,n=,s=,a=,y=,o=,u=]}%
- \@EA\toks\@EA2\@EA{\@@pba}%
- \@EA\toks\@EA4\@EA{\@@pbs}%
- \toks0={\ignorespaces #2}%
- \setxvalue{pbdk-\@@pbk}{\@@pbk}
- \setxvalue{pbda-\@@pbk}{\the\toks2}
- \setxvalue{pbdy-\@@pbk}{\@@pby}
- \setxvalue{pbds-\@@pbk}{\the\toks4}
- \setxvalue{pbdn-\@@pbk}{\@@pbn}
- \setxvalue{pbdt-\@@pbk}{\@@pbt}
- \setxvalue{pbdo-\@@pbk}{\@@pbo}
- \setxvalue{pbdu-\@@pbk}{\@@pbu}
- \setxvalue{pbdd-\@@pbk}{\the\toks0}
- \xdef\allrefs{\allrefs,\@@pbk}%
- \egroup
- \catcode`\%=\bibmodsavedpercent\relax }
-
-% intialization of the order-list:
-
-\let\allrefs\empty
-
-%D The next macro is needed because the number command of the
-%D publist sometimes needs to fetch something from the current
-%D item (like the 'short' key). For this, the ID of the current
-%D item is passed in the implict parameter \type{\@@pbk}
-
-\def\makepbkvalue#1{\def\@@pbk{#1}}
-
-%D
-
-\newif\ifinpublist
-
-% from Hans
-
-\def\ignoresectionconversion
- {\let\@@sectionconversion\secondoftwoarguments}
-
-\let\normaldosetfilterlevel\dosetfilterlevel
-
-\def\patcheddosetfilterlevel#1#2% beware: this one is \let
- {\bgroup
- \ignoresectionconversion
- \edef\askedlevel{#1}%
- \edef\askedfilter{#2}%
-% \message{ASKD: \meaning\askedlevel}%
-% \message{PREV: \meaning\v!previous}%
- \ifx\askedlevel\v!current
- \dosetcurrentlevel\askedlevel
- \else\ifx\askedlevel\v!previous
- \dosetpreviouslevel\askedlevel
- \else\ifx\askedlevel\v!all
- \global\chardef\alltoclevels\plusone
- \else\ifx\askedlevel\v!text
- \global\chardef\alltoclevels\plusone
- \else
- \edef\byaskedlevel{\csname\??by\askedlevel\endcsname}%
- \ifx\byaskedlevel\v!text
- \dosettextlevel\askedlevel
- \else
- \dosetotherlevel\askedlevel
- \fi
- \fi\fi\fi\fi
- % experiment
- \ifx\askedfilter\empty \else
- \xdef\currentlevel{\currentlevel\sectionseparator\askedfilter}%
- \fi
- \egroup}
-
-
-\unless\ifcsname currentlocationrefence\endcsname
-
-\let\currentlocationreference\empty
-
-\def\dogetreferenceelements#1#2#3#4#5%
- {\chardef\currentreferencetype=\ifx#1\relax0\else#1\fi\relax
- \ifnum\currentreferencetype<2
- \edef\currentpagereference{#2}%
- \let \currentdatareference\empty
- \edef\currentlocationreference{#2}%
- \ifx\currentpagereference \empty
- \let\currentfolioreference\folio
- \else
- \def \currentpagereference {\referencepagenumber[#2]}%
- \edef\currentfolioreference{\dosplitofffoliopart[#2]}%
- \fi
- \edef\currentrealreference{#3}%
- \settextreferences#4\end
- \ifnum0#5<\crossreferencenumber
- \forwardreferencetrue
- \else
- \forwardreferencefalse
- \fi
- \else
- \let \currentlocationreference\empty
- \edef\currentrealreference {#3}%
- \def \currentdatareference {#2}%
- \let \currentfolioreference\folio
- \settextreferences#4\end
- \forwardreferencefalse
- \fi
- \ifodd\currentreferencetype
- \realreferencepagefalse
- \else
- \docheckrealreferencepage\currentrealreference
- \ifrealreferencepage \else
- \docheckrealreferencepage\currentdatareference
- \fi
- \fi}
-
-\fi
-
-\def\filllocalpublist%
- {\doifdefinedelse{\alltoclevels}
- {\let\dosetfilterlevel\patcheddosetfilterlevel
- \dosettoclevel\??li{pubs}%
- \let\dosetfilterlevel\normaldosetfilterlevel }%
- {\dosettoclevel\??li{pubs}}%
- \global\let\glocalpublist\empty
- \doloop
- {\doifdefinedelse
- {\r!cross cite-\jobname-\recurselevel}
- {\doifreferencefoundelse
- {cite-\jobname-\recurselevel}
- {\@EA\doifreglevelelse\@EA[\currentlocationreference]
- {\@EA\doglobal\@EA\addtocommalist\@EA
- {\currenttextreference}\glocalpublist}{}}
- {}}%
- {\exitloop}}%
- \let\localpublist\glocalpublist}
-
-%
-\def\typesetpubslist
- {\dobeginoflist
- \edef\askedlevel{\csname \??li pubs\c!criterium\endcsname}%
- \ifx\askedlevel\v!all
- \def\bibrefprefix{}%
- \else %
- \preparebibrefprefix
- \fi
- \ifsortbycite
- \filllocalpublist
- \iftypesetall
- \let\localallrefs\allrefs
- \processcommacommand[\localpublist]\typesetapublication
- \def\removefromallrefs##1%
- {\removefromcommalist{##1}\localallrefs }%
- \processcommacommand[\localpublist]\removefromallrefs
- \processcommacommand[\localallrefs]\typesetapublication
- \else
- \processcommacommand[\localpublist]\typesetapublication
- \fi
- \else
- \iftypesetall
- \processcommacommand[\allrefs]\typesetapublication
- \else
- %
- \filllocalpublist
- \processcommacommand[\allrefs]\maybetypesetapublication
- \fi
- \fi
- \doendoflist }
-
-\newif\ifinpublist
-\def\maybetypesetapublication#1%
- {\global\inpublistfalse
- \def\test{#1}%
- \def\runtest##1%
- {\def\tempa{##1}\ifx \test\tempa \global\inpublisttrue \fi}%
- \processcommacommand[\localpublist]\runtest
- \ifinpublist \typesetapublication{#1}\fi}
-
-\def\initializepubslist
- {\edef\@@pbnumbering{\@@pbnumbering}%
- \ifautohang
- \ifx\@@pbnumbering\v!short
- \setbox\scratchbox\hbox{\@@pbnumbercommand{\getvalue{\??li pubs\c!samplesize}}}%
- \else\iftypesetall
- \setbox\scratchbox\hbox{\@@pbnumbercommand{\getvalue{\??li pubs\c!totalnumber}}}%
- \else
- \setbox\scratchbox\hbox{\@@pbnumbercommand{\numreferred}}%
- \fi\fi
- \edef\samplewidth{\the\wd\scratchbox}%
- \setuplist[pubs][\c!width=\samplewidth,\c!distance=0pt]%
- \ifx\@@pbnumbering\v!short
- \def\@@pblimitednumber##1{\hbox to \samplewidth
- {\@@pbnumbercommand{\getvalue{pbds-\@@pbk}}}}%
- \else \ifx \@@pbnumbering\v!bib
- \def\@@pblimitednumber##1{\hbox to \samplewidth
- {\@@pbnumbercommand{\getvalue{pbdn-\@@pbk}}}}%
- \else
- \def\@@pblimitednumber##1{\hbox to \samplewidth{\@@pbnumbercommand{##1}}}%
- \fi \fi
- \else
- \ifx\@@pbnumbering\v!short
- \doifemptyelse
- {\getvalue{\??li pubs\c!width}}
- {\def\@@pblimitednumber##1{\hbox
- {\@@pbnumbercommand{\getvalue{pbds-\@@pbk}}}}}%
- {\def\@@pblimitednumber##1{\hbox to \getvalue{\??li pubs\c!width}%
- {\@@pbnumbercommand{\getvalue{pbds-\@@pbk}}}}}%
- \else \ifx \@@pbnumbering\v!bib
- \doifemptyelse
- {\getvalue{\??li pubs\c!width}}
- {\def\@@pblimitednumber##1{\hbox
- {\@@pbnumbercommand{\getvalue{pbdn-\@@pbk}}}}}%
- {\def\@@pblimitednumber##1{\hbox to \getvalue{\??li pubs\c!width}%
- {\@@pbnumbercommand{\getvalue{pbdn-\@@pbk}}}}}%
- \else
- \doifemptyelse
- {\getvalue{\??li pubs\c!width}}
- {\def\@@pblimitednumber##1{\hbox{\@@pbnumbercommand{##1}}}}%
- {\def\@@pblimitednumber##1{\hbox to \getvalue{\??li pubs\c!width}{\@@pbnumbercommand{##1}}}}%
- \fi
- \fi
- \fi
- \ifx\@@pbnumbering\v!no
- \setuplist[pubs][\c!numbercommand=,\c!symbol=\v!none,\c!textcommand=\outdented]%
- \else
- \setuplist[pubs][\c!numbercommand=\@@pblimitednumber]%
- \fi
- \doifelsevalue
- {\??pv datamaybeyear}{\v!off}{\def\maybeyear##1{}}{\def\maybeyear##1{##1}}%
- \forgetall % bugfix 2005/03/18
-}
-
-
-\def\outdented#1% move to supp-box ?
- {\hskip -\hangindent #1}
-
-
-%D The full list of publications
-
-\def\completepublications
- {\dosingleempty\docompletepublications}
-
-\def\bibdogetupsometextprefix#1#2#3%
- {\ifcsname#2#1#3\endcsname
- \csname#2#1#3\endcsname
- \else\ifcsname\??la#1\c!default\endcsname
- \@EA\ifx\csname\??la#1\c!default\endcsname\empty
- \ifcsname#2#3\endcsname
- \csname#2#3\endcsname
- \else\ifcsname#2\s!en#3\endcsname
- \csname#2\s!en#3\endcsname
- \fi\fi
- \else
- \expandafter\bibdogetupsometextprefix
- \csname\??la#1\c!default\endcsname{#2}{#3}%
- \fi
- \else
- \ifcsname#2#3\endcsname
- \csname#2#3\endcsname
- \else\ifcsname#2\s!en#3\endcsname
- \csname#2\s!en#3\endcsname
- \fi\fi
- \fi\fi}
-
-\def\docompletepublications[#1]%
- {\begingroup
- \setuplist[pubs][\c!criterium=\v!previous,#1]
- \begingroup
- \let\handletextprefix\firstoftwoarguments
- \edef\headtextpubs{\bibdogetupsometextprefix\headlanguage\c!title{pubs}}%
- \doifdefinedelse
- {\??pv data\v!title}
- {\doifemptyelsevalue
- {\??pv data\v!title}
- {\expanded{\systemsuppliedtitle[pubs]{\headtextpubs}}}%
- {\expanded{\getvalue{\??pv data\v!title}{\headtextpubs}}}%
- }%
- {\expanded{\systemsuppliedtitle[pubs]{\headtextpubs}}}%
- \endgroup
- \dodoplacepublications }
-
-%D And the portion with the entries only.
-
-\def\placepublications
- {\dosingleempty\doplacepublications}
-
-\def\doplacepublications[#1]%
- {%\getparameters[\??pv data][#1]
- \begingroup
- \setuplist[pubs][\c!criterium=\v!previous,#1]%
- \dodoplacepublications }%
-
-\def\dodoplacepublications%
- {\initializepubslist
- \doifelsevalue
- {\??li pubs\c!option}{\v!continue}%
- {}%
- {\global\let\bibcounter\!!zerocount }%
- \inpublisttrue
- \typesetpubslist
- \inpublistfalse
- \endgroup }
-
-
-%D \subsubject{What's in a publication}
-%D
-
-\unexpanded\def\typesetapublication#1%
- {\doifsomething{#1}{\doglobal\increment\bibcounter
- \bgroup
- \makepbkvalue{#1}%
- \ifgridsnapping
- \snaptogrid\vbox{\dodolistelement{pubs}{}{\bibcounter}%
- {\expanded{\reference[\bibrefprefix#1]{\bibcounter}}%
- \strut \dotypesetapublication{#1}\strut }{}{}}%
- \else
- \dodolistelement{pubs}{}{\bibcounter}%
- {\expanded{\reference[\bibrefprefix#1]{\bibcounter}}%
- \strut \dotypesetapublication{#1}\strut }{}{}%
- \fi
- \egroup }}
-
-\def\dotypesetapublication#1%
- {\bgroup
- \def\@@currentalternative{data}%
- \processcommacommand[\bibcommandlist,crossref]\clearbibitem
- \processcommalist [artauthor,author,editor]\clearbibitemtwo
- \processcommacommand[\bibcommandlist]\bibitemdefs
- \processcommalist [artauthor,author,editor,crossref]\bibitemdefs
- \let\biblanguage\empty
- \getvalue{pbdd-#1}%
- \ifcsname pbdt-#1\endcsname \bibalternative{\getvalue{pbdt-#1}}\fi
- \egroup }
-
-
-%D An afterthought
-
-\def\maybeyear#1{}
-
-%D An another
-
-\def\noopsort#1{}
-
-%D This is the result of bibtex's `language' field.
-
-\def\setbiblanguage#1#2{\setvalue{\??pb @lang@#1}{#2}}
-
-\def\lang#1%
- {\def\biblanguage{#1}%
- \ifcsname \??pb @lang@#1\endcsname
- \expanded{\language[\getvalue{\??pb @lang@#1}]}%
- \fi \ignorespaces}
-
-
-%D \subject{Citations}
-
-%D \macros{cite,bibref}
-%D
-%D The indirection with \type{\dobibref} allows \LATEX\ style
-%D \type{\cite} commands with a braced argument (these might appear
-%D in included data from the \type{.bib} file).
-
-\unexpanded\def\cite
- {\doifnextcharelse{[}
- {\dodocite}
- {\dobibref}}
-
-\def\dobibref#1%
- {\docite[#1][]}
-
-\def\dodocite[#1]%
- {\startstrictinspectnextcharacter
- \dodoubleempty\dododocite[#1]}
-
-\def\dododocite[#1][#2]{%
- \stopstrictinspectnextcharacter
- \docite[#1][#2]}
-
-\def\docite[#1][#2]%
- {\begingroup
- \setupinteraction[\c!style=]%
- \edef\temp{#2}%
- \ifx\empty\temp \secondargumentfalse
- \else \secondargumenttrue \fi
- \ifsecondargument
- \processcommalist[#2]\docitation
- \doifassignmentelse
- {#1}%
- {\getparameters[LO][\c!alternative=,\c!extras=,#1]%
- \edef\@@currentalternative{\LOalternative}%
- \ifx\@@currentalternative\empty
- \edef\@@currentalternative{\@@citedefault}%
- \fi
- \ifx\LOextras\empty
- \setupcite[\@@currentalternative][#1]%
- \else
- \expandafter\ifx\csname LOright\endcsname \relax
- \edef\LOextras{{\LOextras\bibalternative\c!right}}%
- \else
- \edef\LOextras{{\LOextras\LOright}}%
- \fi
- \expanded{\setupcite[\@@currentalternative][#1,\c!right=\LOextras]}%
- \fi
- }%
- {\def\@@currentalternative{#1}}%
- \expanded{%
- \processaction[\csname @@pv\@@currentalternative \c!compress\endcsname]}
- [ \v!yes=>\bibcitecompresstrue,
- \v!no=>\bibcitecompressfalse,
- \s!default=>\bibcitecompresstrue,
- \s!unknown=>\bibcitecompresstrue]%
- \getvalue{bib\@@currentalternative ref}[#2]%
- \else
- \processcommalist[#1]\docitation
- \expanded{\processaction[\csname @@pv\@@citedefault \c!compress\endcsname]}
- [ \v!yes=>\bibcitecompresstrue,
- \v!no=>\bibcitecompressfalse,
- \s!default=>\bibcitecompresstrue,
- \s!unknown=>\bibcitecompresstrue]%
- \edef\@@currentalternative{\@@citedefault}%
- \getvalue{bib\@@citedefault ref}[#1]%
- \fi
- \endgroup}
-
-%D \macros{nocite}
-
-\def\nocite[#1]%
- {\processcommalist[#1]\addthisref
- \processcommalist[#1]\docitation }
-
-%D \macros{setupcite}
-
-\def\setupcite{\dodoubleempty\dosetupcite}
-
-\def\dosetupcite[#1][#2]%
- {\ifsecondargument
- \def\dodosetupcite##1{\getparameters[\??pv##1][#2]}%
- \processcommalist[#1]\dodosetupcite
- \else % default case
- \getparameters[\??pv\@@citedefault][#1]%
- \fi }
-
-
-%D Low-level stuff
-
-\def\getcitedata#1[#2]#3[#4]#5to#6%
- {\bgroup
- \addthisref{#4}%
- \dofetchapublication{#4}%
- \doifdefinedelse{@@pb@bib#2}%
- {\xdef#6{\getvalue{@@pb@bib#2}}}%
- {\xdef#6{\getvalue{@@pb@#2}}}%
- \egroup }
-
-
-\def\dofetchapublication#1%
- {\makepbkvalue{#1}%
- \processcommacommand[\bibcommandlist,crossref]\clearbibitem
- \processcommalist [artauthor,author,editor]\clearbibitemtwo
- \processcommacommand[\bibcommandlist]\bibitemdefs
- \processcommalist [artauthor,author,editor,crossref]\bibitemdefs
- \getvalue{pbdd-#1}}
-
-%D This new version writes a reference out to the tui file for every
-%D \type{\cite}. This will allow backlinking.
-%D
-%D Some special care is needed so that references are not added from
-%D weird locations like in the TOC or within a \type{\setbox} command.
-
-\newcounter\citationnumber
-
-\def\docitation#1{%
- \iftrialtypesetting \else
- \ifdoinpututilities\else
- \doglobal\increment\citationnumber
- \expanded{\rawreference{}{cite-\jobname-\citationnumber}{#1}}%
- \fi \fi }
-
-
-%D \macros{numreferred,doifreferredelse,addthisref,publist}
-%D
-%D The interesting command here is \type{\addthisref}, which maintains
-%D the global list of references.
-%D
-%D \type{\numreferred} is needed to do automatic calculations on
-%D the label width, and \type{\doifreferredelse} will be used
-%D to implement \type{criterium=cite}.
-
-\newcounter\numreferred
-
-\long\def\doifreferredelse#1{\doifdefinedelse{pbr-#1}}
-
-\def\addthisref#1%
- {\doifundefinedelse{pbr-#1}
- {\setxvalue{pbr-#1}{\citationnumber}%
- \doglobal\increment\numreferred
- \ifx\publist\empty \gdef\publist{#1}\else\appended\gdef\publist{,#1}\fi}
- {\setxvalue{pbr-#1}{\getvalue{pbr-#1},\citationnumber}}}
-
-\let\publist\empty
-
-%D \macros{doifbibreferencefoundelse}
-%D
-%D Some macros to fetch the information provided by
-%D \type{\startpublication}.
-
-\def\doifbibreferencefoundelse#1#2#3%
- {\doifdefinedelse{pbdk-#1}
- {#2}
- {\showmessage\m!bib{5}{#1 is unknown}#3}}
-
-%D \macros{ixbibauthoryear,thebibauthors,thebibyears}
-%D
-%D If compression of \type{\cite}'s argument expansion is on,
-%D the macros that deal with authors and years call this internal
-%D command to do the actual typesetting.
-%D
-%D Two entries with same author but with different years may
-%D be condensed into ``Author (year1,year2)''. This is about the
-%D only optimization that makes sense for the (author,year)
-%D style of citations (years within one author have to be unique
-%D anyway so no need to test for that, and ``Author1, Author2 (year)''
-%D creates more confusion than it does good).
-%D
-%D In the code below,
-%D the macro \type{\thebibauthors} holds the names of the alternative
-%D author info fields for the current list. This is a commalist,
-%D and \type{\thebibyears} holds the (collection of) year(s) that go with
-%D this author (possibly as a nested commalist).
-%D
-%D There had better be an author for all cases, but there
-%D does not have to be year info always. \type{\thebibyears} is
-%D pre-initialized because this makes the insertion macros simpler.
-%D
-%D In `normal' \TeX, of course there are expansion problems again.
-
-\def\ixbibauthoryear#1#2#3#4%
- {\bgroup
- \gdef\ixlastcommand {#4}%
- \gdef\ixsecondcommand{#3}%
- \gdef\ixfirstcommand {#2}%
- \glet\thebibauthors \empty
- \glet\thebibyears \empty
- \getcommalistsize[#1]%
- \ifbibcitecompress
- \dorecurse\commalistsize{\xdef\thebibyears{\thebibyears,}}%
- \processcommalist[#1]\docompressbibauthoryear
- \else
- \processcommalist[#1]\donormalbibauthoryear
- \fi
- \egroup
- \dobibauthoryear}
-
-%D \macros{dodobibauthoryear}
-%D
-%D This macro only has to make sure that the lists
-%D \type{\thebibauthors} and \type{\thebibyears} are printed.
-
-\def\dobibauthoryear
- {\scratchcounter\zerocount
- \getcommacommandsize[\thebibauthors]%
- \edef\authorcount{\commalistsize}%
- \@EA\processcommalist\@EA[\thebibauthors]\dodobibauthoryear}
-
-\def\dodobibauthoryear#1%
- {\advance\scratchcounter\plusone
- \edef\wantednumber{\the\scratchcounter}%
- \getfromcommacommand[\thebibyears][\wantednumber]%
- \@EA\def\@EA\currentbibyear\@EA{\commalistelement}%
- \setcurrentbibauthor{#1}%
- \ifnum\scratchcounter=\plusone
- \ixfirstcommand
- \else\ifnum \scratchcounter=\authorcount\relax
- \ixlastcommand
- \else
- \ixsecondcommand
- \fi\fi}
-
-\def\setcurrentbibauthor#1%
- {\getcommacommandsize[#1]%
- \ifcase\commalistsize
- % anonymous?
- \def\currentbibauthor{}%
- \or
- \def\currentbibauthor{#1}%
- \or
- \expanded{\docurrentbibauthor#1}%
- \else
- \handlemultiplebibauthors{\commalistsize}{#1}%
- \fi }
-
-
-\newcount\citescratchcounter
-
-\def\handlemultiplebibauthors#1#2%
- {\citescratchcounter 0
- \def\currentbibauthor{}%
- \def\bibprocessauthoritem##1%
- {\advance\citescratchcounter1
- \ifnum \citescratchcounter=#1\relax
- \edef\currentbibauthor{\currentbibauthor##1}%
- \else \ifnum\numexpr\citescratchcounter+1 = #1\relax
- \edef\currentbibauthor{\currentbibauthor ##1\bibalternative{andtext}}%
- \else
- \edef\currentbibauthor{\currentbibauthor ##1\bibalternative{namesep}}%
- \fi
- \fi }%
- \processcommalist[#2]\bibprocessauthoritem }
-
-
-\setupcite
- [author,authoryear,authoryears]
- [\c!namesep={, }]
-
-%D This discovery of authoretallimit is not the best one,
-%D but it will do for now.
-
-\def\docurrentbibauthor#1,#2%
- {\doifemptyelse{#2}
- {\def\currentbibauthor{#1\bibalternative{otherstext}}}
- {\@EA
- \ifx\csname \??pv\@@currentalternative authoretallimit\endcsname\relax
- \edef\currentbibauthor{#1\bibalternative{andtext}#2}%
- \else
- \edef\currentbibauthor{#1%
- \ifcase0\bibalternative{authoretallimit}\relax\or
- \bibalternative{otherstext}\else\bibalternative{andtext}#2\fi}%
- \fi}}
-
-%D This is not the one Hans made for me, because I need a global
-%D edef, and the \type{\robustdoifinsetelse} doesn't listen to
-%D \type{\doglobal }
-
-\def\robustaddtocommalist#1#2% {item} \cs
- {\robustdoifinsetelse{#1}#2\resetglobal
- {\dodoglobal\xdef#2{\ifx#2\empty\else#2,\fi#1}}}
-
-
-%D \macros{donormalbibauthoryear}
-%D
-%D Now we get to the macros that fill the two lists.
-%D The `simple' one really is quite simple.
-
-\def\donormalbibauthoryear#1%
- {\addthisref{#1}%
- \def\myauthor{Xxxxxxxxxx}%
- \def\myyear{0000}%
- \doifbibreferencefoundelse{#1}
- {\def\myauthor{{\getvalue{pbda-#1}}}%
- \def\myyear {\getvalue{pbdy-#1}}}%
- {}%
- \@EA\doglobal\@EA\appendtocommalist\@EA{\myauthor}\thebibauthors
- \@EA\doglobal\@EA\appendtocommalist\@EA{\myyear }\thebibyears}
-
-%D \macros{docompressbibauthoryear}
-%D
-%D So much for the easy parts. Nothing at all will be done if
-%D the reference is not found or the reference does not contain
-%D author data. No questions marks o.s.s. (to be fixed later)
-
-\def\docompressbibauthoryear#1%
- {\addthisref{#1}%
- \def\myauthor{Xxxxxxxxxx}%
- \def\myyear {0000}%
- \doifbibreferencefoundelse{#1}
- {\xdef\myauthor{\csname pbda-#1\endcsname }%
- \xdef\myyear {\csname pbdy-#1\endcsname }}
- {}%
- \ifx\myauthor\empty\else
- \checkifmyauthoralreadyexists
- \findmatchingyear
- \fi}
-
-%D two temporary counters. One of these two can possibly be replaced
-%D by \type{\scratchcounter}.
-
-\newcount\bibitemcounter
-\newcount\bibitemwanted
-
-%D The first portion is simple enough: if this is the very first author
-%D it is quite straightforward to add it. \type{\bibitemcounter} and
-%D \type{\bibitemwanted} are needed later to insert the year
-%D information in the correct item of \type{\thebibyears}
-
-\def\checkifmyauthoralreadyexists
- {\doifemptyelsevalue{thebibauthors}
- {\global\bibitemwanted \plusone
- \global\bibitemcounter \plusone
- \xdef\thebibauthors{{\myauthor}}}
- {% the next weirdness is because according to \getcommalistsize,
- % the length of \type{[{{},{}}]} is 2.
- \@EA\getcommalistsize\@EA[\thebibauthors,]%
- \global\bibitemcounter\commalistsize
- \global\advance\bibitemcounter\minusone
- \global\bibitemwanted \zerocount
- \processcommacommand[\thebibauthors]\docomparemyauthor}}
-
-%D The outer \type{\ifnum} accomplishes the addition of
-%D a new author to \type{\thebibauthors}. The messing about with
-%D the two counters is again to make sure that \type{\thebibyears}
-%D will be updated correctly.If the author {\it was} found,
-%D the counters will stay at their present values and everything
-%D will be setup properly to insert the year info.
-
-\def\docomparemyauthor#1%
- {\global\advance\bibitemwanted \plusone
- \def\mytempc{#1}%
-% \message{authors: \myauthor <=>\mytempc \ifx\mytempc\myauthor :Y \else :N
-% \meaning \myauthor, \meaning\mytempc\fi (\the\bibitemwanted = \the\bibitemcounter)}%
- \ifx\mytempc\myauthor
- \quitcommalist
- \else
- \ifnum\bibitemwanted = \bibitemcounter\relax
- \global\advance\bibitemwanted \plusone
- \global\bibitemcounter\bibitemwanted\relax
- \@EA\doglobal\@EA\robustaddtocommalist\@EA{{\myauthor}}\thebibauthors
- \fi
- \fi}
-
-%D This macro should be clear now.
-
-\def\findmatchingyear
- {\edef\wantednumber{\the\bibitemwanted}%
- \getfromcommacommand[\thebibyears][\wantednumber]%
- \ifx\commalistelement\empty
- \edef\myyear{{\myyear}}%
- \else
- \edef\myyear{{\commalistelement, \myyear}}%
- \fi
- \edef\newcommalistelement{\myyear}%
- \doglobal\replaceincommalist \thebibyears \wantednumber}
-
-
-%D \macros{preparebibrefprefix}
-%D
-%D The reference list only writes bare references when the criterium
-%D is `all'. Otherwise, a prefix is added to make sure that pdfTeX
-%D does not encounter duplicate named references. On the generation
-%D side, this is not a big problem. \type{\preparebibrefprefix}
-%D creates a suitable string to prepend if a prefix is needed.
-%D
-%D Because this macro is used within \type{\cite } that itself
-%D can be used within lists like the table of contents, it needs
-%D to save and restore \type{\savedalltoclevels} and
-%D \type{\currentlevel} (\type{\dosetfilterlevel} needs to change
-%D their values globally).
-
-\def\preparebibrefprefix
- {\chardef\savedalltoclevels \alltoclevels
- \let\savedcurrentlevel\currentlevel
- \let\dosetfilterlevel\patcheddosetfilterlevel
- \dosettoclevel\??li{pubs}%
- \edef\bibrefprefix{\@@sectiontype\currentlevel\sectionseparator}%
- \let\dosetfilterlevel\normaldosetfilterlevel
- \global\let\currentlevel\savedcurrentlevel
- \global\chardef\alltoclevels \savedalltoclevels }
-
-%D \macros{preparebibreflist}
-%D
-%D But this optional prefixing is a bit of a problem on the
-%D other side. We would like to do \type{\goto{}[article-full]}
-%D but can't do it like that, because the actual label may be
-%D \type{1:2:0:3:4:article-full]} or so. The problem is solved
-%D by building a commalist that looks like this:
-%D \starttyping
-%D \def\bibreflist%
-%D {1:2:0:3:4:article-full,
-%D 1:2:0:3:article-full,
-%D 1:2:0:article-full,
-%D 1:2:article-full,
-%D 1:article-full,
-%D article-full}
-%D \stoptyping
-
-\def\preparebibreflist#1%
- {\let\bibreflist\empty
- \def\storeitem##1%
- {\ifx\bibreflist\empty
- \edef\prefix{##1\sectionseparator}%
- \edef\bibreflist{\prefix#1,#1}%
- \else
- \edef\prefix{\prefix##1\sectionseparator}%
- \edef\bibreflist{\prefix#1,\bibreflist}%
- \fi}%
- \expanded{\processseparatedlist[\bibrefprefix][\sectionseparator]}\storeitem }
-
-%D \macros{gotobiblink,inbiblink,atbiblink}
-%D
-%D The final task is looping over that list until a match is found.
-
-\newif\ifbibreffound
-
-\def\gotobiblink#1[#2]%
- {\bgroup
- \preparebibrefprefix
- \preparebibreflist{#2}%
- \global\bibreffoundfalse
- \def\setuplink##1%
- {\ifbibreffound\else
- \doifreferencefoundelse
- {##1}
- {\global\bibreffoundtrue \goto{#1}[##1]}%
- {}\fi}%
- \processcommacommand[\bibreflist]\setuplink
- \ifbibreffound \else \unknownreference{#2}\fi
- \egroup }
-
-\def\atbiblink[#1]%
- {\bgroup
- \preparebibrefprefix
- \preparebibreflist{#1}%
- \global\bibreffoundfalse
- \def\setuplink##1%
- {\ifbibreffound\else
- \doifreferencefoundelse
- {##1}
- {\global\bibreffoundtrue \at[##1]}%
- {}\fi}%
- \processcommacommand[\bibreflist]\setuplink
- \ifbibreffound \else \unknownreference{#1}\fi
- \egroup }
-
-\def\inbiblink[#1]%
- {\bgroup
- \preparebibrefprefix
- \preparebibreflist{#1}%
- \global\bibreffoundfalse
- \def\setuplink##1%
- {\ifbibreffound\else
- \doifreferencefoundelse
- {##1}
- {\global\bibreffoundtrue \in[##1]}%
- {}\fi}%
- \processcommacommand[\bibreflist]\setuplink
- \ifbibreffound \else \unknownreference{#1}\fi
- \egroup }
-
-%D \macros{bibauthoryearref,bibauthoryearsref,bibauthorref,bibyearref}
-%D
-%D Now that all the hard work has been done, these are simple.
-%D \type{\ixbibauthoryearref} stores the data in the macros
-%D \type{\currentbibauthor} and \type{\currentbibyear}.
-
-\def\ifbibinteractionelse%
- {\iflocation
- \edef\test{\bibalternative\c!interaction}%
- \ifx\test\v!stop
- \@EA\@EA\@EA\secondoftwoarguments
- \else
- \@EA\@EA\@EA\firstoftwoarguments
- \fi
- \else
- \@EA\secondoftwoarguments
- \fi
- }
-
-\def\bibmaybeinteractive#1#2%
- {\ifbibcitecompress #2\else
- \ifbibinteractionelse{\gotobiblink{#2}[#1]}{#2}\fi }
-
-\def\bibauthoryearref[#1]%
- {\ixbibauthoryear{#1}%
- {\bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween
- \bibalternative\v!left{\currentbibyear}\bibalternative\v!right}}
- {\bibalternative\c!pubsep
- \bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween
- \bibalternative\v!left {\currentbibyear}\bibalternative\v!right}}
- {\bibalternative\c!lastpubsep
- \bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween
- \bibalternative\v!left {\currentbibyear}\bibalternative\v!right}}}
-
-\def\bibauthoryearsref[#1]%
- {\bibalternative\v!left
- \ixbibauthoryear{#1}
- {\bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween{\currentbibyear}}}
- {\bibalternative\c!pubsep
- \bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween{\currentbibyear}}}
- {\bibalternative\c!lastpubsep
- \bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween{\currentbibyear}}}%
- \bibalternative\v!right}
-
-\def\bibauthorref[#1]%
- {\bibalternative\v!left
- \ixbibauthoryear{#1}%
- {\bibmaybeinteractive{#1}{{\currentbibauthor}}}
- {\bibalternative\c!pubsep \bibmaybeinteractive{#1}{{\currentbibauthor}}}
- {\bibalternative\c!lastpubsep\bibmaybeinteractive{#1}{{\currentbibauthor}}}%
- \bibalternative\v!right}
-
-\def\bibyearref[#1]%
- {\bibalternative\v!left
- \ixbibauthoryear{#1}%
- {\bibmaybeinteractive{#1}{{\currentbibyear}}}
- {\bibalternative\c!pubsep \bibmaybeinteractive{#1}{{\currentbibyear}}}
- {\bibalternative\c!lastpubsep\bibmaybeinteractive{#1}{{\currentbibyear}}}%
- \bibalternative\v!right}
-
-%D ML problems:
-
-%D \macros{bibshortref,bibkeyref,bibpageref,bibtyperef,bibserialref}
-%D
-%D There is hardly any point in trying to compress these. The only
-%D thing that needs to be done is making sure that
-%D the separations are inserted correctly. And that is
-%D what \type{\refsep} does.
-
-\newif\iffirstref
-
-\def\refsep{\iffirstref\firstreffalse\else\bibalternative\c!pubsep\fi}
-
-\def\bibshortref[#1]%
- {\bibalternative\v!left
- \firstreftrue\processcommalist[#1]\dobibshortref
- \bibalternative\v!right}
-
-\def\dobibshortref#1%
- {\addthisref{#1}\refsep
- \doifbibreferencefoundelse{#1}{\gotobiblink{\getvalue{pbds-#1}}[#1]}
- {\unknownreference{#1}}}
-
-
-\def\bibserialref[#1]%
- {\bibalternative\v!left
- \firstreftrue\processcommalist[#1]\dobibserialref
- \bibalternative\v!right}
-
-\def\dobibserialref#1%
- {\addthisref{#1}\refsep
- \doifbibreferencefoundelse{#1}{\gotobiblink{\getvalue{pbdn-#1}}[#1]}
- {\unknownreference{#1}}}
-
-\def\bibkeyref[#1]%
- {\bibalternative\v!left
- \firstreftrue\processcommalist[#1]\dobibkeyref
- \bibalternative\v!right}
-
-\def\dobibkeyref#1%
- {\addthisref{#1}\refsep\gotobiblink{#1}[#1]}
-
-\def\gotoDOI#1#2%
- {\ifbibinteractionelse
- {\useURL[bibfooDoi#1][#2]%
- \useURL[bibfoo#1][http://dx.doi.org/#2]%
- \goto{\url[bibfooDoi#1]}[url(bibfoo#1)]}
- {\hyphenatedurl{#2}}}
-
-\def\bibdoiref[#1]%
- {\bibalternative\v!left
- \firstreftrue\processcommalist[#1]\dobibdoiref
- \bibalternative\v!right}
-
-\def\dobibdoiref#1%
- {\addthisref{#1}\refsep
- \doifbibreferencefoundelse{#1}{\expanded{\gotoDOI{#1}{\getvalue{pbdo-#1}}}}
- {\unknownreference{#1}}}
-
-
-\def\biburlref[#1]%
- {\bibalternative\v!left
- \firstreftrue\processcommalist[#1]\dobiburlref
- \bibalternative\v!right}
-
-\def\gotoURL#1#2%
- {\ifbibinteractionelse
- {\useURL[bibfoo#1][#2]\goto{\url[bibfoo#1]}[url(bibfoo#1)]}
- {\hyphenatedurl{#2}}}
-
-\def\dobiburlref#1%
- {\addthisref{#1}\refsep
- \doifbibreferencefoundelse{#1}{\expanded{\gotoURL{#1}{\getvalue{pbdu-#1}}}}
- {\unknownreference{#1}}}
-
-\def\bibtyperef[#1]%
- {\bibalternative\v!left
- \firstreftrue\processcommalist[#1]\dobibtyperef
- \bibalternative\v!right}
-
-\def\dobibtyperef#1%
- {\addthisref{#1}\refsep
- \doifbibreferencefoundelse{#1}{\gotobiblink{\getvalue{pbdt-#1}}[#1]}
- {\unknownreference{#1}}}
-
-\def\bibpageref[#1]%
- {\bibalternative\v!left
- \firstreftrue\processcommalist[#1]\dobibpageref
- \bibalternative\v!right}
-
-\def\dobibpageref#1%
- {\addthisref{#1}\refsep
- \ifbibinteractionelse{\atbiblink[#1]}{{\referencingfalse\at[#1]}}}
-
-\def\bibdataref[#1]%
- {\bibalternative\v!left
- \firstreftrue\processcommalist[#1]\dobibdata
- \bibalternative\v!right}
-
-\def\dobibdata#1%
- {\addthisref{#1}\refsep
- \doifbibreferencefoundelse{#1}{\dotypesetapublication{#1}}
- {\unknownreference{#1}}}
-
-\let\bibnoneref\nocite
-
-%D \macros{bibnumref}
-%D
-%D It makes sense to try and compress the argument list of
-%D \type{\bibnumref}. There are two things involved: the actual
-%D compression, and a sort routine. The idea is to store the
-%D found values in a new commalist called \type{\therefs}.
-
-%D But that is not too straight-forward, because \type{\in} is
-%D not expandable,
-%D so that the macro \type{\expandrefs} is needed.
-
-\def\expandrefs#1%
- {\bgroup
- \preparebibrefprefix
- \preparebibreflist{#1}%
- \global\bibreffoundfalse
- \def\setuplink##1%
- {\ifbibreffound\else
- \doifreferencefoundelse
- {##1}
- {\global\bibreffoundtrue
- \@EA\doglobal\@EA\addtocommalist\@EA{\reftypet}\therefs }%
- {}\fi}%
- \processcommacommand[\bibreflist]\setuplink
- \ifbibreffound \else \showmessage\m!bib{5}{#1 unknown}%
- \doglobal\addtocommalist{0}\therefs\fi
- \egroup }
-
-
-%D But at least the actual sorting code is simple (note that sorting
-%D a list with exactly one entry fails to return anything, which
-%D is why the \type{\ifx} is needed).
-
-\def\bibnumref[#1]%
- {\bibalternative\v!left
- \penalty\!!tenthousand
- \processcommalist[#1]\addthisref
- \firstreftrue
- \ifbibcitecompress
- \glet\therefs\empty
- \processcommalist[#1]\expandrefs
- \sortcommacommand[\therefs]\donumericcompare
- \ifx\empty\sortedcommalist\else
- \let\therefs\sortedcommalist
- \fi
- \compresscommacommandnrs[\therefs]%
- \processcommacommand[\compressedlist]\verysimplebibnumref
- \else
- \processcommalist[#1]\dosimplebibnumref
- \fi
- \bibalternative\v!right}
-
-\def\dosimplebibnumref #1%
- {\refsep\ifbibinteractionelse
- {\inbiblink[#1]}{{\referencingfalse\inbiblink[#1]}}}
-
-\def\verysimplebibnumref#1{\doverysimplebibnumref#1}
-
-\def\doverysimplebibnumref#1#2%
- {\refsep
- \ifcase#1\relax \unknownreference{#1}\else
- \def\tempa{#2}\ifx\empty\tempa#1\else#1\bibalternative\c!inbetween#2\fi
- \fi}
-
-%D By request from Sanjoy. This makes it easier to implement
-%D \type{\citeasnoun}.
-
-\def\bibauthornumref[#1]%
- {\getcommalistsize[#1]%
- \global\bibitemcounter\commalistsize
- \firstreftrue
- \processcommalist[#1]\dobibauthornumref }
-
-\def\dobibauthornumref#1%
- {\addthisref{#1}\refsep
- \doifbibreferencefoundelse{#1}
- {\getvalue{pbda-#1}%
- \bibalternative\c!inbetween
- \bibalternative\v!left
- \ifbibinteractionelse{\inbiblink[#1]}
- {{\referencingfalse\inbiblink[#1]}}%
- \bibalternative\v!right}
- {\unknownreference{#1}}}
-
-%D And some defaults are loaded from bibl-apa:
-
-\setuppublications
- [\v!month\v!conversion=,\c!alternative=apa]
-
-\loadmarkfile{t-bib}
-
-\preloadbiblist
-
-\protect \endinput
diff --git a/tex/context/bib/t-bibltx.tex b/tex/context/bib/t-bibltx.tex
deleted file mode 100644
index cb9e787ad..000000000
--- a/tex/context/bib/t-bibltx.tex
+++ /dev/null
@@ -1,75 +0,0 @@
-%D \module
-%D [ file=t-bibltx,
-%D version=2005.01.04,
-%D title=\CONTEXT\ Publication Module,
-%D subtitle=Publications,
-%D author={Taco Hoekwater},
-%D date=\currentdate,
-%D copyright={Public Domain}]
-%C
-%C Donated to the public domain.
-
-%D \macros{newcommand}
-%D
-%D Just about all databases define something that uses
-%D \type {\newcommand}. This fake version does not cover
-%D everything \type {\newcommand} does, but it should be
-%D enough for simple definitions like the ones found in
-%D \BIBTEX\ files.
-
-\unprotect
-
-\def\@star@or@long#1%
- {\doifnextcharelse*{\afterassignment#1\let\next=}{#1}}
-
-\def\newcommand
- {\@star@or@long\new@command}
-
-\def\new@command#1%
- {\@testopt{\@newcommand#1}0}
-
-\def\@newcommand#1[#2]%
- {\doifnextcharelse[{\@xargdef#1[#2]}{\@argdef#1[#2]}}
-
-\long\def\@argdef#1[#2]#3%
- {\@yargdef#1\@ne{#2}{#3}}
-
-\long\def\@xargdef#1[#2][#3]#4%
- {\@EA\def\@EA#1\@EA{\@EA\do@testopt\@EA#1\csname\string#1\endcsname{#3}}%
- \@EA\@yargdef\csname\string#1\endcsname\tw@{#2}{#4}}
-
-\def\@testopt#1#2%
- {\doifnextcharelse[{#1}{#1[#2]}}
-
-\def\do@testopt#1%
- {\expandafter\@testopt}
-
-\long\def\@yargdef#1#2#3%
- {\!!counta#3\relax
- \advance \!!counta \@ne
- \let\@hash@\relax
- \edef\!!tempa{\ifx#2\tw@ [\@hash@1]\fi}%
- \!!countb #2%
- \loop
- \ifnum\!!countb <\!!counta
- \edef\!!tempa{\!!tempa\@hash@\the\!!countb}%
- \advance\!!countb \@ne
- \repeat
- \let\@hash@##%
- \long\@EA\def\@EA#1\!!tempa}
-
-\long\def\@reargdef#1[#2]%
- {\@yargdef#1\@ne{#2}}
-
-%D Something like the following is needed to support the
-%D average \LATEX-based \BIBTEX\ databases.
-%D
-%D \starttyping
-%D \let\textsc\kap
-%D \def\emph#1{{\em#1}}
-%D \let\sf\ss
-%D \stoptyping
-%D
-%D But we happily leave that to the user.
-
-\protect \endinput
diff --git a/tex/context/interface/cont-cs.xml b/tex/context/interface/cont-cs.xml
index 53d861c90..f8dc85a84 100644
--- a/tex/context/interface/cont-cs.xml
+++ b/tex/context/interface/cont-cs.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?><!-- versions:
+<?xml version="1.0" encoding="UTF-8"?> <!-- versions:
comment : user interface definitions of ConTeXt
diff --git a/tex/context/interface/cont-de.xml b/tex/context/interface/cont-de.xml
index aaea5d00c..aeb0a4acd 100644
--- a/tex/context/interface/cont-de.xml
+++ b/tex/context/interface/cont-de.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?><!-- versions:
+<?xml version="1.0" encoding="UTF-8"?> <!-- versions:
comment : user interface definitions of ConTeXt
diff --git a/tex/context/interface/cont-en.xml b/tex/context/interface/cont-en.xml
index 4f0237627..95e8a4ab9 100644
--- a/tex/context/interface/cont-en.xml
+++ b/tex/context/interface/cont-en.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?><!-- versions:
+<?xml version="1.0" encoding="UTF-8"?> <!-- versions:
comment : user interface definitions of ConTeXt
diff --git a/tex/context/interface/cont-fr.xml b/tex/context/interface/cont-fr.xml
index 690903ca4..3e6df06ed 100644
--- a/tex/context/interface/cont-fr.xml
+++ b/tex/context/interface/cont-fr.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?><!-- versions:
+<?xml version="1.0" encoding="UTF-8"?> <!-- versions:
comment : user interface definitions of ConTeXt
diff --git a/tex/context/interface/cont-it.xml b/tex/context/interface/cont-it.xml
index e2502d5cd..c670feb92 100644
--- a/tex/context/interface/cont-it.xml
+++ b/tex/context/interface/cont-it.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?><!-- versions:
+<?xml version="1.0" encoding="UTF-8"?> <!-- versions:
comment : user interface definitions of ConTeXt
diff --git a/tex/context/interface/cont-nl.xml b/tex/context/interface/cont-nl.xml
index 47ce230b5..3c3fbca5f 100644
--- a/tex/context/interface/cont-nl.xml
+++ b/tex/context/interface/cont-nl.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?><!-- versions:
+<?xml version="1.0" encoding="UTF-8"?> <!-- versions:
comment : user interface definitions of ConTeXt
diff --git a/tex/context/interface/cont-pe.xml b/tex/context/interface/cont-pe.xml
index bcf164d8d..3b1f8c6c0 100644
--- a/tex/context/interface/cont-pe.xml
+++ b/tex/context/interface/cont-pe.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?><!-- versions:
+<?xml version="1.0" encoding="UTF-8"?> <!-- versions:
comment : user interface definitions of ConTeXt
diff --git a/tex/context/interface/cont-ro.xml b/tex/context/interface/cont-ro.xml
index 2f6dd9f3e..e63ca67d1 100644
--- a/tex/context/interface/cont-ro.xml
+++ b/tex/context/interface/cont-ro.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?><!-- versions:
+<?xml version="1.0" encoding="UTF-8"?> <!-- versions:
comment : user interface definitions of ConTeXt
diff --git a/tex/context/interface/t-bib.xml b/tex/context/interface/t-bib.xml
deleted file mode 100644
index faa728fa6..000000000
--- a/tex/context/interface/t-bib.xml
+++ /dev/null
@@ -1,411 +0,0 @@
-<?xml version="1.0"?>
-
-<cd:interface xmlns:cd="http://www.pragma-ade.com/commands"
- name="context/third/t-bib"
- language="all" version="2006.08.04">
-
-<cd:command name="setuppublications" file="t-bib.tex">
- <cd:sequence>
- <cd:string value="setuppublications"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments list="yes">
- <cd:parameter name="alternative">
- <cd:constant type="ams"/>
- <cd:constant type="apa" default="yes"/>
- <cd:constant type="apa-de"/>
- <cd:constant type="apa-fr"/>
- <cd:constant type="aps"/>
- <cd:constant type="num"/>
- <cd:constant type="num-fr"/>
- <cd:constant type="ssa"/>
- </cd:parameter>
- <cd:parameter name="refcommand">
- <cd:constant type="author"/>
- <cd:constant type="authornum"/>
- <cd:constant type="authoryear"/>
- <cd:constant type="authoryears" default="yes"/>
- <cd:constant type="key"/>
- <cd:constant type="num"/>
- <cd:constant type="serial"/>
- <cd:constant type="page"/>
- <cd:constant type="short"/>
- <cd:constant type="type"/>
- <cd:constant type="year"/>
- <cd:constant type="data"/>
- <cd:constant type="doi"/>
- <cd:constant type="url"/>
- </cd:parameter>
- <cd:parameter name="sorttype">
- <cd:constant type="cite" default="yes"/>
- <cd:constant type="bbl"/>
- </cd:parameter>
- <cd:parameter name="criterium">
- <cd:constant type="all" />
- <cd:constant type="cite" default="yes"/>
- </cd:parameter>
- <cd:parameter name="numbering">
- <cd:constant type="yes"/>
- <cd:constant type="no" default="yes"/>
- <cd:constant type="short"/>
- <cd:constant type="bib"/>
- </cd:parameter>
- <cd:parameter name="autohang">
- <cd:constant type="yes"/>
- <cd:constant type="no" default="yes"/>
- </cd:parameter>
- <cd:parameter name="monthconversion">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
-</cd:command>
-
-<cd:command name="setuppublicationlist" file="t-bib.tex">
- <cd:sequence>
- <cd:string value="setuppublicationlist"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments list="yes">
- <cd:parameter name="totalnumber">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="samplesize">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="title">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="maybeyear">
- <cd:constant type="off"/>
- <cd:constant type="on" default="yes"/>
- </cd:parameter>
- <cd:parameter name="criterium">
- <cd:constant type="cd:section"/>
- <cd:constant type="local"/>
- <cd:constant type="previous"/>
- <cd:constant type="current" default="yes"/>
- <cd:constant type="all"/>
- </cd:parameter>
- <cd:parameter name="pagenumber">
- <cd:constant type="yes"/>
- <cd:constant type="no" default="yes"/>
- </cd:parameter>
- <cd:parameter name="artauthor">
- <cd:constant type="\normalauthor"/>
- <cd:constant type="\normalshortauthor"/>
- <cd:constant type="\invertedauthor"/>
- <cd:constant type="\invertedshortauthor" default="yes"/>
- </cd:parameter>
- <cd:parameter name="author">
- <cd:constant type="\normalauthor"/>
- <cd:constant type="\normalshortauthor"/>
- <cd:constant type="\invertedauthor"/>
- <cd:constant type="\invertedshortauthor" default="yes"/>
- </cd:parameter>
- <cd:parameter name="editor">
- <cd:constant type="\normalauthor"/>
- <cd:constant type="\normalshortauthor"/>
- <cd:constant type="\invertedauthor"/>
- <cd:constant type="\invertedshortauthor" default="yes"/>
- </cd:parameter>
- <cd:parameter name="namesep">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="lastnamesep">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="finalnamesep">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="firstnamesep">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="juniorsep">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="vonsep">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="surnamesep">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="authoretallimit">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="authoretaltext">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="authoretaldisplay">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="authorcommand">
- <cd:constant type="cd:threearguments"/>
- </cd:parameter>
- <cd:parameter name="artauthoretallimit">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="artauthoretaltext">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="artauthoretaldisplay">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="artauthorcommand">
- <cd:constant type="cd:threearguments"/>
- </cd:parameter>
- <cd:parameter name="editoretallimit">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="editoretaltext">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="editoretaldisplay">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="editorcommand">
- <cd:constant type="cd:threearguments"/>
- </cd:parameter>
- <cd:inherit name="setuplist"/>
- </cd:assignments>
- </cd:arguments>
-</cd:command>
-
-
-<cd:command name="setupcite" file="t-bib.tex">
- <cd:sequence>
- <cd:string value="setupcite"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords list="yes">
- <cd:constant type="author"/>
- <cd:constant type="year"/>
- <cd:constant type="authoryear"/>
- <cd:constant type="authoryears"/>
- <cd:constant type="key"/>
- <cd:constant type="serial"/>
- <cd:constant type="page"/>
- <cd:constant type="short"/>
- <cd:constant type="type"/>
- <cd:constant type="data"/>
- <cd:constant type="doi"/>
- <cd:constant type="url"/>
- <cd:constant type="num"/>
- </cd:keywords>
- <cd:assignments list="yes">
- <cd:parameter name="andtext">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="otherstext">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="namesep">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="pubsep">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="lastpubsep">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="compress">
- <cd:constant type="yes" default="yes"/>
- <cd:constant type="no"/>
- </cd:parameter>
- <cd:parameter name="inbetween">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="left">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="right">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
-</cd:command>
-
-<cd:command name="setuppublicationlayout" file="t-bib.tex">
- <cd:sequence>
- <cd:string value="setuppublicationlayout"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords list="yes">
- <cd:constant type="article"/>
- <cd:constant type="book"/>
- <cd:constant type="booklet"/>
- <cd:constant type="conference"/>
- <cd:constant type="electronic"/>
- <cd:constant type="inbook"/>
- <cd:constant type="incollection"/>
- <cd:constant type="inproceedings"/>
- <cd:constant type="manual"/>
- <cd:constant type="mastersthesis"/>
- <cd:constant type="misc"/>
- <cd:constant type="patent"/>
- <cd:constant type="periodical"/>
- <cd:constant type="phdthesis"/>
- <cd:constant type="proceedings"/>
- <cd:constant type="standard"/>
- <cd:constant type="techreport"/>
- <cd:constant type="unpublished"/>
- </cd:keywords>
- <cd:content/>
- </cd:arguments>
-</cd:command>
-
-
-<cd:command name="setupbibtex" file="t-bib.tex">
- <cd:sequence>
- <cd:string value="setupbibtex"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments list="yes">
- <cd:parameter name="database">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="sort">
- <cd:constant type="title"/>
- <cd:constant type="author"/>
- <cd:constant type="short"/>
- <cd:constant type="no" default="yes"/>
- <cd:constant type="cd:file"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
-</cd:command>
-
-
-<cd:command name="usepublications" file="t-bib.tex">
- <cd:sequence>
- <cd:string value="usepublications"/>
- </cd:sequence>
- <cd:arguments list="yes">
- <cd:keywords>
- <cd:constant type="cd:file"/>
- </cd:keywords>
- </cd:arguments>
-</cd:command>
-
-
-<cd:command name="publication" file="t-bib.tex" type="environment">
- <cd:sequence>
- <cd:string value="publication"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments list="yes">
- <cd:parameter name="k">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="a">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="y">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="n">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="s">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="t">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="u">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="o">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
-</cd:command>
-
-<cd:command name="cite" file="t-bib.tex">
- <cd:sequence>
- <cd:string value="cite"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords optional="yes">
- <cd:constant type="author"/>
- <cd:constant type="year"/>
- <cd:constant type="authoryear"/>
- <cd:constant type="authoryears"/>
- <cd:constant type="key"/>
- <cd:constant type="serial"/>
- <cd:constant type="page"/>
- <cd:constant type="short"/>
- <cd:constant type="type"/>
- <cd:constant type="doi"/>
- <cd:constant type="data"/>
- <cd:constant type="url"/>
- <cd:constant type="num"/>
- </cd:keywords>
- <cd:reference list="yes"/>
- </cd:arguments>
-</cd:command>
-
-<cd:command name="nocite" file="t-bib.tex">
- <cd:sequence>
- <cd:string value="nocite"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference list="yes"/>
- </cd:arguments>
-</cd:command>
-
-<cd:command name="citealt" file="t-bib.tex">
- <cd:sequence>
- <cd:string value="cite"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments optional="yes" list="yes">
- <cd:parameter name="alternative">
- <cd:constant type="author"/>
- <cd:constant type="year"/>
- <cd:constant type="authoryear"/>
- <cd:constant type="authoryears"/>
- <cd:constant type="key"/>
- <cd:constant type="serial"/>
- <cd:constant type="page"/>
- <cd:constant type="short"/>
- <cd:constant type="type"/>
- <cd:constant type="doi"/>
- <cd:constant type="data"/>
- <cd:constant type="url"/>
- <cd:constant type="num"/>
- </cd:parameter>
- <cd:parameter name="extras">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:inherit name="setupcite"/>
- </cd:assignments>
- <cd:reference list="yes"/>
- </cd:arguments>
-</cd:command>
-
-<cd:command name="placepublications" file="t-bib.tex">
- <cd:sequence>
- <cd:string value="placepublications"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments optional="yes" list="yes">
- <cd:inherit name="setuplist"/>
- </cd:assignments>
- </cd:arguments>
-</cd:command>
-
-<cd:command name="completepublications" file="t-bib.tex">
- <cd:sequence>
- <cd:string value="completepublications"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments optional="yes" list="yes">
- <cd:inherit name="setuplist"/>
- </cd:assignments>
- </cd:arguments>
-</cd:command>
-
-
-</cd:interface>
diff --git a/tex/generic/context/luatex-fonts-merged.lua b/tex/generic/context/luatex-fonts-merged.lua
index d0e7f9ae9..a1775edb5 100644
--- a/tex/generic/context/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
-- merged file : c:/data/develop/context/texmf/tex/generic/context/luatex-fonts-merged.lua
-- parent file : c:/data/develop/context/texmf/tex/generic/context/luatex-fonts.lua
--- merge date : 10/02/09 13:19:15
+-- merge date : 10/16/09 16:21:21
do -- begin closure to overcome local limits and interference
@@ -369,6 +369,18 @@ function string:split(separator)
return c:match(self)
end
+--~ function lpeg.L(list,pp)
+--~ local p = pp
+--~ for l=1,#list do
+--~ if p then
+--~ p = p + lpeg.P(list[l])
+--~ else
+--~ p = lpeg.P(list[l])
+--~ end
+--~ end
+--~ return p
+--~ end
+
end -- closure
do -- begin closure to overcome local limits and interference
@@ -507,6 +519,14 @@ function table.strip(tab)
return lst
end
+function table.keys(t)
+ local k = { }
+ for key,_ in next, t do
+ k[#k+1] = key
+ end
+ return k
+end
+
local function compare(a,b)
return (tostring(a) < tostring(b))
end
@@ -1279,22 +1299,6 @@ function table.reverse(t)
return tt
end
---~ function table.keys(t)
---~ local k = { }
---~ for k,_ in next, t do
---~ k[#k+1] = k
---~ end
---~ return k
---~ end
-
---~ function table.keys_as_string(t)
---~ local k = { }
---~ for k,_ in next, t do
---~ k[#k+1] = k
---~ end
---~ return concat(k,"")
---~ end
-
function table.insert_before_value(t,value,extra)
for i=1,#t do
if t[i] == extra then
@@ -1561,11 +1565,11 @@ local rootbased = lpeg.P("/") + letter*lpeg.P(":")
-- ./name ../name /name c: :// name/name
function file.is_qualified_path(filename)
- return qualified:match(filename)
+ return qualified:match(filename) ~= nil
end
function file.is_rootbased_path(filename)
- return rootbased:match(filename)
+ return rootbased:match(filename) ~= nil
end
local slash = lpeg.S("\\/")
@@ -2674,11 +2678,12 @@ function nodes.inject_kerns(head,where,keep)
-- if rlmode and rlmode < 0 then
-- n.xoffset = p.xoffset + d[1]
-- else
+local k = wx[p]
+if k then
+ n.xoffset = p.xoffset - d[1] - k[2]
+else
n.xoffset = p.xoffset - d[1]
---~ local k = wx[p]
---~ if k then
---~ wx[n] = k
---~ end
+end
-- end
if mk[p] then
n.yoffset = p.yoffset + d[2]
@@ -3025,7 +3030,6 @@ else do
-- X000 1100 = 12 = 0x1C = leftghost
-- X001 0100 = 20 = 0x14 = rightghost
-
function nodes.protect_glyphs(head)
local done = false
for g in traverse_id(glyph,head) do
@@ -3093,6 +3097,8 @@ if not modules then modules = { } end modules ['font-ini'] = {
--ldx]]--
local utf = unicode.utf8
+local format, serialize = string.format, table.serialize
+local write_nl = texio.write_nl
if not fontloader then fontloader = fontforge end
@@ -3173,7 +3179,24 @@ function fonts.show_char_data(n)
end
local chr = tfmdata.characters[n]
if chr then
- texio.write_nl(table.serialize(chr,string.format("U_%04X",n)))
+ write_nl(format("%s @ %s => U%04X => %s => ",tfmdata.fullname,tfmdata.size,n,utf.char(n)) .. serialize(chr,false))
+ end
+ end
+end
+
+function fonts.show_font_parameters()
+ local tfmdata = fonts.ids[font.current()]
+ if tfmdata then
+ local parameters, mathconstants = tfmdata.parameters, tfmdata.MathConstants
+ local hasparameters, hasmathconstants = parameters and next(parameters), mathconstants and next(mathconstants)
+ if hasparameters then
+ write_nl(format("%s @ %s => parameters => ",tfmdata.fullname,tfmdata.size) .. serialize(parameters,false))
+ end
+ if hasmathconstants then
+ write_nl(format("%s @ %s => math constants => ",tfmdata.fullname,tfmdata.size) .. serialize(mathconstants,false))
+ end
+ if not hasparameters and not hasmathconstants then
+ write_nl(format("%s @ %s => no parameters and/or mathconstants",tfmdata.fullname,tfmdata.size))
end
end
end
@@ -3442,6 +3465,7 @@ function tfm.do_scale(tfmtable, scaledpoints)
t.unicodes = tfmtable.unicodes
t.indices = tfmtable.indices
t.marks = tfmtable.marks
+t.colorscheme = tfmtable.colorscheme
t.descriptions = descriptions
if tfmtable.fonts then
t.fonts = table.fastcopy(tfmtable.fonts) -- hm also at the end
@@ -5205,7 +5229,7 @@ otf.features.default = otf.features.default or { }
otf.enhancers = otf.enhancers or { }
otf.glists = { "gsub", "gpos" }
-otf.version = 2.628 -- beware: also sync font-mis.lua
+otf.version = 2.631 -- beware: also sync font-mis.lua
otf.pack = true -- beware: also sync font-mis.lua
otf.syncspace = true
otf.notdef = false
@@ -5325,6 +5349,7 @@ local enhancers = {
"patch bugs",
"merge cid fonts", "prepare unicode", "cleanup ttf tables", "compact glyphs", "reverse coverage",
"cleanup aat", "enrich with features", "add some missing characters",
+--~ "reorganize mark classes",
"reorganize kerns", -- moved here
"flatten glyph lookups", "flatten anchor tables", "flatten feature tables",
"prepare luatex tables",
@@ -5477,6 +5502,22 @@ end
-- todo: normalize, design_size => designsize
+otf.enhancers["reorganize mark classes"] = function(data,filename)
+ if data.mark_classes then
+ local unicodes = data.luatex.unicodes
+ local reverse = { }
+ for name, class in next, data.mark_classes do
+ local t = { }
+ for s in gmatch(class,"[^ ]+") do
+ t[unicodes[s]] = true
+ end
+ reverse[name] = t
+ end
+ data.luatex.markclasses = reverse
+ data.mark_classes = nil
+ end
+end
+
otf.enhancers["prepare luatex tables"] = function(data,filename)
data.luatex = data.luatex or { }
local luatex = data.luatex
@@ -5780,12 +5821,21 @@ otf.enhancers["analyse subtables"] = function(data,filename)
end
local flags = gk.flags
if flags then
+--~ gk.flags = { -- forcing false packs nicer
+--~ (flags.ignorecombiningmarks and "mark") or false,
+--~ (flags.ignoreligatures and "ligature") or false,
+--~ (flags.ignorebaseglyphs and "base") or false,
+--~ flags.r2l or false,
+--~ }
gk.flags = { -- forcing false packs nicer
- (flags.ignorecombiningmarks and "mark") or false,
- (flags.ignoreligatures and "ligature") or false,
- (flags.ignorebaseglyphs and "base") or false,
- flags.r2l or false
+ ((flags.ignorecombiningmarks or flags.mark_class) and "mark") or false,
+ ( flags.ignoreligatures and "ligature") or false,
+ ( flags.ignorebaseglyphs and "base") or false,
+ flags.r2l or false,
}
+--~ if flags.mark_class then
+--~ gk.markclass = luatex.markclasses[flags.mark_class]
+--~ end
end
end
end
@@ -7394,6 +7444,7 @@ local trace_bugs = false trackers.register("otf.bugs", function
local trace_details = false trackers.register("otf.details", function(v) trace_details = v end)
local trace_applied = false trackers.register("otf.applied", function(v) trace_applied = v end)
local trace_steps = false trackers.register("otf.steps", function(v) trace_steps = v end)
+local trace_skips = false trackers.register("otf.skips", function(v) trace_skips = v end)
trackers.register("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end)
trackers.register("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end)
@@ -8764,16 +8815,26 @@ end
-- we don't need to pass the currentcontext, saves a bit
-- make a slow variant then can be activated but with more tracing
+local function show_skip(kind,chainname,char,ck,class)
+ if ck[9] then
+ logwarning("%s: skipping char %s (%s) in rule %s, lookuptype %s (%s=>%s)",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10])
+ else
+ logwarning("%s: skipping char %s (%s) in rule %s, lookuptype %s",cref(kind,chainname),gref(char),class,ck[1],ck[2])
+ end
+end
+
local function normal_handle_contextchain(start,kind,chainname,contexts,sequence,cache)
-- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6]
local flags, done = sequence.flags, false
local skipmark, skipligature, skipbase = flags[1], flags[2], flags[3]
local someskip = skipmark or skipligature or skipbase -- could be stored in flags for a fast test (hm, flags could be false !)
+ local markclass = sequence.markclass
for k=1,#contexts do
local match, current, last = true, start, start
local ck = contexts[k]
local sequence = ck[3]
local s = #sequence
+ -- f..l = mid string
if s == 1 then
-- never happens
match = current.id == glyph and current.subtype<256 and current.font == currentfont and sequence[1][current.char]
@@ -8801,9 +8862,13 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
local ccd = descriptions[char]
if ccd then
local class = ccd.class
+--~ if class == skipmark or class == skipligature or class == skipbase or (markclass and not markclass[char]) then
if class == skipmark or class == skipligature or class == skipbase then
---~ if someskip and class == skipmark or class == skipligature or class == skipbase then
+--~ if someskip and (class == skipmark or class == skipligature or class == skipbase) then
-- skip 'm
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
last = last.next
elseif sequence[n][char] then
if n < l then
@@ -8831,6 +8896,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
-- end
end
if match and f > 1 then
+ -- before
local prev = start.prev
if prev then
local n = f-1
@@ -8843,9 +8909,13 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
local ccd = descriptions[char]
if ccd then
local class = ccd.class
+--~ if class == skipmark or class == skipligature or class == skipbase or (markclass and not markclass[char]) then
if class == skipmark or class == skipligature or class == skipbase then
--~ if someskip and class == skipmark or class == skipligature or class == skipbase then
-- skip 'm
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
elseif sequence[n][char] then
n = n -1
else
@@ -8882,9 +8952,10 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
end
end
if match and s > l then
+ -- after
local current = last.next
if current then
- -- removed optimiziation for s-l == 1, we have to deal with marks anyway
+ -- removed optimization for s-l == 1, we have to deal with marks anyway
local n = l + 1
while n <= s do
if current then
@@ -8895,9 +8966,13 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
local ccd = descriptions[char]
if ccd then
local class = ccd.class
+--~ if class == skipmark or class == skipligature or class == skipbase or (markclass and not markclass[char]) then
if class == skipmark or class == skipligature or class == skipbase then
--~ if someskip and class == skipmark or class == skipligature or class == skipbase then
-- skip 'm
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
elseif sequence[n][char] then
n = n + 1
else
@@ -9058,6 +9133,8 @@ end
local resolved = { } -- we only resolve a font,script,language pair once
+-- todo: pass all these 'locals' in a table
+
function fonts.methods.node.otf.features(head,font,attr)
if trace_steps then
checkstep(head)
@@ -9217,6 +9294,7 @@ function fonts.methods.node.otf.features(head,font,attr)
-- sequence kan weg
local ok
start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,1)
+--~ texio.write_nl(tostring(lookupname),tostring(lookupmatch),tostring(ok))
if ok then
success = true
end